shell - 我如何让 Tcl 的 exec 运行一个命令,该命令的参数包含带空格的引号字符串?

标签 shell tcl exec eval quoting

我想使用 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/

相关文章:

Linux shell 脚本 - 获取字符串中数字的总和,但同时将字符串与总和保持一致

linux - 在每个文件夹中制作文件夹和文件的脚本

tomcat - 在 apache tomcat 上运行 Tcl

tcl - 使用值被 {} 包围的列表模式

bash - 如何执行shell命令

linux - 用于递减传递参数的 Shell 脚本

linux - 从expect/tcl 向perl 脚本传递多个参数

python - 不受信任的用户不应运行哪些内置函数?

java - 在java中用不同的用户调用外部进程

linux - 是否可以验证 tar.gz 文件是否已损坏