I'm trying to exec
from tcl, passing a variable that can start with <
, (or |
or >
) as an argument. tcl seems to think I want to direct the input of a file to the command instead of using a literal angle bracket.
set cmd "<hi>"
exec echo $cmd # couldn't read file "hi>"
eval exec [list echo $cmd] # couldn't execute "echo <hi>"
eval exec {*}[list echo $cmd] # couldn't read file "hi>"
I cant even get the expected <hi>
when hard coding a string
eval exec {*}{"echo" <hi>} # couldn't read file "hi>"
exec echo {"<hi>"} # "<hi>" # but I don't want quotes
exec echo {\<hi>} # \<hi> # nor a leading \
exec echo {<hi>} # couldn't read file "hi>"
exec echo {*}[list "<hi>"] # '
eval exec echo [list "<hi>"] # '
This is similar to TCL exec with special characters in list, but <
throws off the solutions there
Also, maybe worth noting
1) having extra args allows |
to go through, but not <
eval exec {*}[list echo {|foo bar} ] # |foo bar # WORKS? WHAT?
eval exec {*}[list echo {|foo} ] # illegal use of | or |& in command
eval exec {*}[list echo {<foo bar} ] # couldn't read file "foo"
2) extra spaces or characters are enough to side step the issue (but how to use those with user provided/parsed variable)
exec echo { <hi>} # <hi> # with leading space
exec echo { |hi} # |hi # with leading space
exec echo [list " " $cmd] # { } <hi> # not useful
exec echo {*}[list " " $cmd] # couldn't read file "hi>"
exec echo [join [list "" $cmd]] # <hi> # leading space
exec echo [string trim [join [list "" $cmd]]] # couldn't read file "hi>"
one way around this (stealing a bit from @jerry) is to write the command to a temp file and run it with a shell
set f [file tempfile fn "/tmp/cmd"]
# open $fn w # unnecessary
puts $f $cmd
close $f
set shcmd "echo \"`cat $fn`\""
exec sh -c $shcmd
file delete $fn