我想使用 pgrep
从命令行查找进程的 pid。在 shell 中,这样做是这样的:
pgrep -u andrew -fx 'some_binary -c some_config.cfg'
但是当我从 Tcl 尝试这个时,像这样:
exec pgrep -u $user -fx $cmdLine
我得到:
pgrep: invalid option -- '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 shell 使用单引号但具有可嵌套的额外好处;这就是大括号真正 在 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
命令生成列表,但它使用规范形式,这也是 保证 的脚本片段strong> 缺少“惊喜”替换或单词边界。
如果您使用的是更新版本的 Tcl(特别是 8.5 或更高版本),您将能够使用扩展。这旨在专门与 list
一起很好地工作,并且在大约 99% 的情况下无需使用 eval
。这会改变:
eval exec $cmd
进入:
exec {*}$cmd
当 cmd
持有规范列表时,它们实际上运行相同的操作时,语义有点不同除外。 (当你处理非规范列表时,差异就出现了,其中 eval
会做各种各样的事情——想象一下 set cmd {ab [exit] cd}
造成的破坏,这是一个有效但非规范的列表——而扩展只是强制事物成为一个列表并使用列表中的单词而不作进一步解释。)
关于shell - 我如何让 Tcl 的 exec 运行一个命令,该命令的参数包含带空格的引号字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41398072/