I want to use pgrep
to find the pid of a process from its command-line. In the shell, this is done as so:
pgrep -u andrew -fx 'some_binary -c some_config.cfg'
But when I try this from Tcl, like this:
exec pgrep -u $user -fx $cmdLine
I get:
pgrep: invalid option -- 'c'
Which makes sense, because it's seeing this:
pgrep -u andrew -fx some_binary -c some_config.cfg
But it's the same when I add single quotes:
exec pgrep -u $user -fx '$cmdLine'
And that also makes sense, because single quotes aren't special to Tcl. I think it's consider 'some_binary
an argument, then the -c
, then the some_config.cfg'
.
I've also tried:
exec pgrep -u $user -fx {$cmdLine}
and
set cmd "pgrep -u $user -fx '$cmdLine'"
eval exec $cmd
to no avail.
From my reading it seems the {*}
feature in Tcl 8.5+ might help, but my company infrastructure runs Tcl 8.0.5.
The problem is partially that
'
means nothing at all to Tcl, and partially that you're losing control of where the word boundaries are.Firstly, double check that this actually works:
or perhaps this (Tcl uses
{
…}
like Unix shells use single quotes but with the added benefit of being nestable; that's what braces really do in Tcl):What ought to work is this:
where you have set
cmdLine
to exactly the characters that you want to have in it (check by printing out if you're unsure; what matters is the value in the variable, not the quoted version that you write in your script). I'll use theset cmdLine "…"
form below, but really use whatever you need for things to work.Now, if you are going to be passing this past
eval
, then you should uselist
to add in the extra quotes that you need to make things safe:The
list
command produces lists, but it uses a canonical form that is also a script fragment that is guaranteed to lack “surprise” substitutions or word boundaries.If you were on a more recent version of Tcl (specifically 8.5 or later), you'd be able to use expansion. That's designed to specifically work very well with
list
, and gets rid of the need to useeval
in about 99% of all cases. That'd change the:into:
The semantics are a bit different except when
cmd
is holding a canonical list, when they actually run the same operation. (The differences come when you deal with non-canonical lists, whereeval
would do all sorts of things — imagine the havoc withset cmd {ab [exit] cd}
, which is a valid but non-canonical list — whereas expansion just forces things to be a list and uses the words in the list without further interpretation.)