TCL/Expect - exec - how to execute program with parameters
Solution 1
The safest way to build a command for exec
is to use Tcl's list
. For example:
% set tcl_version
8.5
% set cmd [list ls -l tmp]
ls -l tmp
% eval exec $cmd
total 32
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 file.txt
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-1.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-2.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-3.dat
% exec {*}$cmd
total 32
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 file.txt
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-1.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-2.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-3.dat
%
Note that {*} is a new syntax of Tcl 8.5 which can help reduce the uses of eval
.
Solution 2
As example for ls
command you can do:
exec {*}ls -lsa {*}[glob *.cpp]
Please have a look at What does {*} do in TCL?
![Wakan Tanka](https://i.stack.imgur.com/aCLot.jpg?s=256&g=1)
Wakan Tanka
Enthusiastic and passionate for computers and technology, my workhorses: perl, bash, python, tcl/tk, R. LaTeX, Unix
Updated on June 04, 2022Comments
-
Wakan Tanka about 2 years
I am experimenting with TCL command
exec
intclsh
and here are my results:% set show_me_dir "ls" ls % exec $show_me_dir VboxSharedFolder % set show_me_dir "ls -la" ls -la % exec $show_me_dir couldn't execute "ls -la": no such file or directory % set show_me_dir {ls -la} ls -la % exec $show_me_dir couldn't execute "ls -la": no such file or directory % ls -la total 141 d---------+ 1 wakatana Domain Users 0 Jan 22 19:12 . d---------+ 1 wakatana Domain Users 0 Apr 16 2014 .. ----------+ 1 wakatana Domain Users 20214 Jan 23 18:43 .bash_history ----------+ 1 wakatana Domain Users 1494 Apr 15 2014 .bash_profile ----------+ 1 wakatana Domain Users 7593 Jan 22 19:03 .bashrc d---------+ 1 wakatana Domain Users 0 Jan 15 14:56 VboxSharedFolder %
Can somebody please explain how can I execute command with arguments?
Edit:
The following example from Expanding a list of parameters in Tcl and eval article was big eye opener of what is going on here:
The variable
$action
is only expanded into the string"piemiddle apple"
AFTER the command line has been split into its individual parameters:% set action {piemiddle apple} % set $action can't read "piemiddle apple": no such variable
Result:
set
command "sees" one argument, equivalent to:% set {piemiddle apple}
The expand operator allows you to specify that a variable is to be expanded BEFORE the command line is split into individual parameters:
% set action {piemiddle apple} % set {*}$action apple
Result:
set
command "sees" two arguments, equivalent to:% set piemiddle apple
In earlier versions of Tcl, the eval command was the recommended alternative and it remains available today.
% set action {piemiddle apple} % eval set $action apple
Another examples which proves functionality of expansion operator:
% set {*}"name Linus" Linus % puts $name Linus % % % set distro Unbuntu Unbuntu % set {*}"linux $distro" Unbuntu % puts $linux Unbuntu % %
Finally the discovery that
exec
needs command as it's first argument and first command option as it's second argument etc.% exec "ls" "-la" total 137 d---------+ 1 wakatana Domain Users 0 Jan 22 19:12 . d---------+ 1 wakatana Domain Users 0 Apr 16 2014 .. ----------+ 1 wakatana Domain Users 20214 Jan 23 18:43 .bash_history ----------+ 1 wakatana Domain Users 1494 Apr 15 2014 .bash_profile ----------+ 1 wakatana Domain Users 7593 Jan 22 19:03 .bashrc d---------+ 1 wakatana Domain Users 0 Jan 15 14:56 VboxSharedFolder % % % exec "ls -la" couldn't execute "ls -la": no such file or directory
-
Wakan Tanka over 9 yearsIsn't TCL list just ordinary strings where each word is separated with space? I think
set cmd [list ls -la /tmp]
andset cmd "ls -la /tmp"
are the same. -
Donal Fellows over 9 yearsNote that 8.4 is out of support now. We will no longer do even security patches for it. Not that we're aware of anything in it that needs patches that wouldn't be better fixed by just going to 8.5 anyway. The level of compatibility between the two is mostly very high (unless you're relying on integers being a fixed width, in which case your code already isn't portable).
-
pynexj over 9 years@WakanTanka: The are not the same. For example, just think how you can do the same thing as
set cmd [list ls -l "foo bar.txt"]
without usinglist
. Andset cmd [list echo \[]
? -
Wakan Tanka over 9 years@whjm: e.g. by using escaping with backslash? It's a little bit ugly syntax but it will work I suppose.
-
pynexj over 9 yearsYes by using backslash escapes we can construct valid lists. But it's not always easy and it's error prone.
-
Wakan Tanka over 9 years@whjm: I agree, but as I said those two mentioned constructions does exactly the same thing in the end.
-
pynexj over 9 years@WakanTanka: For this specific case, yes. But don't think you can always construct correct lists this way especially when you don't know in advance what the data would look like. :)