bashargumentscommand-line-argumentsexpectargument-passing

TCL/Expect equivalent of Bash $@ or how to pass arguments to spawned process in TCL/Expect


If somebody wants to call external program (which was passed as a Bash argument) from Bash and also pass it command line options (which were also passed as a Bash arguments) the solution is fairy simple:

TCL_SCRIPT="$1"
shift
TCL_SCRIPT_ARGUMENTS="$@"
expect -f "$TCL_SCRIPT" "$TCL_SCRIPT_ARGUMENTS" 2>&1

Is something similar possible in TCL/Expect ?

EDIT: So far I've come with this hack (there are Bash equivalents in comments), which seems that it is working. Can somebody explain lshift procedure?

# http://wiki.tcl.tk/918#pagetocc7993a2b
proc lshift {inputlist} {
  upvar $inputlist argv
  set arg  [lindex $argv 0]
  #set argv [lrange $argv 1 end] ;# below is much faster - lreplace can make use of unshared Tcl_Obj to avoid alloc'ing the result
  set argv [lreplace $argv[set argv {}] 0 0]
  return $arg
}

# BASH: TCL_SCRIPT="$1"
set script [lindex $argv 0]

# BASH: shift
lshift argv

# BASH: TCL_SCRIPT_ARGUMENTS="$@"
set arguments $argv

Solution

  • To literally translate your example

    set program [lindex $argv 0]
    set arguments [lrange $argv 1 end]
    spawn $program {*}$arguments
    

    {*} is Tcl's "list expansion" syntax (rule 5 of Tcl's 12 rules of syntax). It splits a list into its element in the current command.

    If $argv is foo bar baz, then

    spawn [lindex $argv 0] [lrange $argv 1 end]
    

    will invoke foo with 1 argument: "bar baz"

    spawn [lindex $argv 0] {*}[lrange $argv 1 end]
    

    will invoke foo with 2 arguments: "bar" and "baz"


    Tangentially, I would code your lshift proc like this:

    proc lshift {varname} {      
        upvar 1 $varname var
        set var [lassign $var first]
        return $first
    }
    

    Then:

    expect1.6> set argv {foo bar baz}
    foo bar baz
    expect1.7> set script [lshift argv]
    foo
    expect1.8> set script
    foo
    expect1.9> set argv
    bar baz