TCL/Expect - exec - how to execute program with parameters

10,722

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?

Share:
10,722
Wakan Tanka
Author by

Wakan Tanka

Enthusiastic and passionate for computers and technology, my workhorses: perl, bash, python, tcl/tk, R. LaTeX, Unix

Updated on June 04, 2022

Comments

  • Wakan Tanka
    Wakan Tanka about 2 years

    I am experimenting with TCL command exec in tclsh 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
    Wakan Tanka over 9 years
    Isn't TCL list just ordinary strings where each word is separated with space? I think set cmd [list ls -la /tmp] and set cmd "ls -la /tmp" are the same.
  • Donal Fellows
    Donal Fellows over 9 years
    Note 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
    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 using list. And set cmd [list echo \[]?
  • Wakan Tanka
    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
    pynexj over 9 years
    Yes by using backslash escapes we can construct valid lists. But it's not always easy and it's error prone.
  • Wakan Tanka
    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
    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. :)