在subprocess.call()

时间:2017-01-09 17:03:36

标签: python python-2.7 subprocess

只要我安装了相应的程序 - 默认情况下在Ubuntu 16.04中没有安装fortune - 我可以使用以下命令让我的计算机的语音到文本功能告诉我重新开始工作,然后从fortune中读到一个鼓舞人心的话:

spd-say "get back to work and remember `fortune`"

这里我使用带反引号的命令替换将调用fortune命令的结果添加到要读取的文本字符串中。在Python中,我可以使用subprocess来执行此操作:

subprocess.call(['spd-say', 'get back to work'])

但是,使用反引号替换命令似乎不起作用:

subprocess.call(['spd-say', 'get back to work and remember `fortune`'])

在这种情况下,我会听到:“重新开始工作并记住财富”。我假设这是因为subprocess传递的是单引号字符串,这种命令替换只能在双引号字符串中使用。

我尝试了各种解决方案,包括在单引号内使用双引号,双引号,但我认为它仍然传递一个带双引号的单引号字符串而不是双引号字符串。

我也尝试将整个命令编写为单个字符串,然后使用shlex.split()将其分解:

import shlex
command = 'spd-say "get back to work and remember `fortune`"'
command_args = shlex.split(command)

但是这给了我:

['spd-say', 'get back to work and remember `fortune`']

同样,没有双引号。

有没有办法强制用双引号包装单个参数(如果这确实是问题),或者以上述方式将fortune命令的输出传递给spd-say subprocess.call()

1 个答案:

答案 0 :(得分:2)

扩展命令替换是一个shell操作。如果没有shell=True,那么 就没有subprocess操作中涉及的shell。这通常是非常理想的行为:如果您将文件名作为输入传递,则不希望包含$(rm -rf $HOME)的文件名(是的,所有这些字符在典型的UNIX系统上的文件名中都是合法的)导致内容被删除。

但是,如果你确定你想要进行命令替换,那就是需要进行shell评估的地方:

subprocess.call('spd-say "get back to work and remember $(fortune)"', shell=True)

...相当于以下内容,没有 shell=True

subprocess.call(['sh', '-c', 'spd-say "get back to work and remember $(fortune)"'])

顺便说一句,如果你传递一个带有shell=True的数组,只有第一个参数被解析为一个脚本(因此有命令替换和执行扩展);其他参数是文字参数,可由脚本本身解释:

subprocess.call(
  ['spd-say "$1 $(fortune)"',                     # this is a script
   "_",                                           # this is a literal for $0 in the script
   "get back to work, don't $(rm), and remember"  # this is a literal for $1 in the script
  ], shell=True)

此处未执行$(rm),因为只将第一个列表元素('spd-say "$1 $(fortune)"')中的内容视为脚本文本。