我想使用 pgrep
从其命令行中找到一个过程的pid。在外壳中,这样做是这样做的:
pgrep -u andrew -fx 'some_binary -c some_config.cfg'
但是,当我从TCL尝试一下时,如下:
exec pgrep -u $user -fx $cmdLine
我得到:
pgrep:无效选项 - 'c'
这是有道理的,因为它看到了:
pgrep -u andrew -fx some_binary -c some_config.cfg
,但是当我添加单引号时是一样的:
exec pgrep -u $user -fx '$cmdLine'
这也很有意义,因为单引号对TCL并不特别。我认为这是'some_binary
一个参数,然后是-c
,然后是some_config.cfg'
。
我也尝试了:
exec pgrep -u $user -fx {$cmdLine}
和
set cmd "pgrep -u $user -fx '$cmdLine'"
eval exec $cmd
无济于事。
从我的阅读中,TCL 8.5 中的{*}
功能似乎有帮助,但是我的公司基础架构运行TCL 8.0.5。
问题部分是'
对TCL根本没有任何意义,部分原因是您正在失去对单词边界所在位置的控制。
首先,仔细检查这实际上有效:
exec pgrep -u $user -fx "some_binary -c some_config.cfg"
或也许此(TCL使用{
…}
,例如Unix shells使用单引号,但具有可嵌套的额外好处;这就是braces 真正的在tcl中):
exec pgrep -u $user -fx {some_binary -c some_config.cfg}
应该有效的是:
set cmdLine "some_binary -c some_config.cfg"
exec pgrep -u $user -fx $cmdLine
在哪里将cmdLine
设置为恰好 您想拥有的字符(如果不确定,请打印出来;重要的是变量中的值,而不是引用的版本您在脚本中写下)。我将在下面使用set cmdLine "…"
表格,但实际上使用您需要的一切工作。
现在,如果您要通过过去的eval
,则应使用list
添加您需要确保事物安全的额外报价:
set cmdLine "some_binary -c some_config.cfg"
set cmd [list pgrep -u $user -fx $cmdLine]
eval exec $cmd
list
命令会产生列表,但它使用 canonical form ,它也是一个脚本片段,它是保证缺乏"惊喜"替换或单词边界。
如果您使用的是最新版本的TCL(特别是8.5或更高版本),则可以使用扩展。这是专门针对list
的专门工作的,并且摆脱了在所有情况中约99%使用eval
的需求。这会改变:
eval exec $cmd
进入:
exec {*}$cmd
语义有些不同,除了 cmd
实际运行相同的操作时持有规范列表时。(当您处理非规范列表时,差异是出现的, eval
会做各种各样的事情 - 想象一下set cmd {ab [exit] cd}
的破坏,这是一个有效但非典型的列表,而扩展只是迫使事物成为列表并使用列表并使用列表中的单词没有进一步的解释。)
由于您使用旧版本,因此必须确保将eval
看到的内容转换为正确引用的TCL字符串。
单语引号什么都不做。exec
不使用它们,也不通过。exec
利用基础exec(3)
系统调用,除非您故意使用以下内容: /bin/sh -c "some-cmd some-arg"
调用外壳并将重新解释命令行。
您要做的就是构造eval
将其解释为引用的TCL字符串的字符串。您可以使用" {part1 part2}"或" " part1 part2 "这些构造。
首先,一个小测试脚本以验证参数是否正确传递:
#!/bin/bash
for i in "$@"; do
echo $i
done
然后tcl脚本:
#!/usr/bin/tclsh
exec ./t.sh -u andrew -fx "some_binary -c some_config.cfg" >@ stdout
eval exec ./t.sh -u andrew -fx "{some_binary -c some_config.cfg}"
>@ stdout
eval exec ./t.sh -u andrew -fx ""some_binary -c some_config.cfg""
>@ stdout
# the list will be converted to a string that is already properly
# quoted for interpretation by eval.
set cmd [list ./t.sh -u andrew -fx "some_binary -c some_config.cfg"]
eval exec $cmd >@ stdout