是否可以在传递给子进程的shell字符串中进行变量替换?

时间:2013-09-23 20:53:40

标签: python

假设我有这个:

>>> grepstring="mystring"
>>> p = subprocess.Popen("ls -l | grep grepstring", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

如何在grepstring来电中将mystring替换为subprocess.Popen

2 个答案:

答案 0 :(得分:6)

使用字符串插值,例如str.format()

subprocess.Popen("ls -l | grep {}".format(grepstring), ...)

但请注意warnings on the subprocess documentation关于在shell中执行不受信任的命令。

答案 1 :(得分:3)

如果可能的话,正确的做法是进行变量替换。事实上,首先不要使用shell。你真正想要的是传递grep一个论点;你需要通过变量替换来做到这一点的唯一原因是你没有运行grep,你正在运行一个shell并试图弄清楚如何让它为你运行grep你想要的。

如果你只想做一个shell ${grepstring}的等价物,你可以使用Python的字符串处理命令 - 理想情况下str.format,就像Martijn Pieters所说的那样。但是,如果grepstring中有空格,那么这将无效。或特殊的shell字符。或者更糟糕的是,工作,但不是您想要的方式(例如,如果grepstring$(rm -rf /)

您可以尝试编写代码来清理,然后正确引用所有字符串,但这是一个傻瓜的差事。简单的解决方案是除了最简单的情况(比如文字shell管道字符串)之外,不要使用shell。 subprocess文档有关于替换旧函数和shell函数的整个部分,其中包括Replacing shell pipeline

所以:

grepstring="mystring"
p0 = Popen(['ls', '-l'], stdout=PIPE)
p = Popen(['grep', grepstring], stdin=p0.stdout, stdout=PIPE, stderr=PIPE)
p0.stdout.close()

现在,你有p与原始示例中的行为相同,只是grepstring只是Popen的正常参数,而不是你拥有的字符串引用并消毒并填入shell字符串。

如果你正在做很多这样的事情,你可以很容易地把它包起来,或者使用PyPI上的任何69105库来为你做这些(范围从保持简单的库到使用聪明技巧的库)使你的Python管道看起来像bash)。

相关问题