Python Popen grep

6

我希望使用Popen执行以下操作:

grep -i --line-buffered "grave" data/*.txt

当我在shell中运行时,我得到了想要的结果。如果我在测试grep的同一目录下启动Python repl,并按照文档中的指示操作,则可以获得应该是提供给Popen的正确参数列表:

['grep', '-i', '--line-buffered', 'grave', 'data/*.txt']

p = subprocess.Popen(args)的结果是:

grep: data/*.txt: No such file or directory

如果我尝试使用p = subprocess.Popen(args, shell=True),会得到以下结果:

Usage: grep [OPTION]... PATTERN [FILE]...
Try `grep --help' for more information.

请问如何执行所需的过程?我使用的是MacOS Lion操作系统。

2个回答

11
如果你在bash中输入*,那么shell会在执行命令之前将其扩展为所给目录中的文件。但是Python的Popen并不这样做,因此当你像那样调用Popen时,你告诉grep在data目录中有一个名为*.txt的文件,而不是所有.txt文件。由于该文件不存在,你会得到预期的错误。
要解决这个问题,你可以通过将shell=True传递给Popen来告诉Python通过shell运行命令:
subprocess.Popen('grep -i --line-buffered grave data/*.txt', shell=True)

被翻译成:

subprocess.Popen(['/bin/sh', '-c', 'grep -i --line-buffered "grave" data/*.txt'])

正如在 Popen文档中所解释的那样

您必须使用字符串而不是列表,因为您希望执行/bin/sh -c "grep -i --line-buffered "grave" data/*.txt"(注意:引号将命令括起来,使其成为sh的单个参数)。如果您使用列表,则会运行此命令:/bin/sh -c grep -i --line-buffered "grave" data/*.txt,这将给出仅运行grep的输出。


4
问题在于shell会为您进行文件名匹配:data/*.txt
您需要自己完成这个过程,例如使用glob模块。
import glob
cmd_line = ['grep', '-i', '--line-buffered', 'grave'] + glob.glob('data/*.txt')

谢谢。为了更好的平台独立性,应该使用os.path.join('data', '*.txt')而不是'data/*.txt'。 - Roman Susi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接