Python Popen grep使用
我想让 Popen 执行以下内容:
grep -i --line-buffered "grave" data/*.txt
当我在命令行中运行这个时,得到了我想要的结果。如果我在测试 grep
的同一个目录下启动一个 Python 交互式环境,并按照文档中的说明操作,我得到了应该传给 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 个回答
问题在于,命令行会自动帮你处理文件匹配,比如说“data/*.txt”这样的写法。
你需要自己来处理这个,比如可以使用 glob
这个模块。
import glob
cmd_line = ['grep', '-i', '--line-buffered', 'grave'] + glob.glob('data/*.txt')
在bash这个命令行工具里,如果你输入*
,它会自动把这个符号替换成当前目录下的所有文件名,然后再执行你输入的命令。而Python里的Popen可没有这个功能,所以当你用Popen这样调用的时候,其实是在告诉grep有一个叫*.txt
的文件在data
目录下,而不是告诉它去找所有的.txt
文件。结果这个文件并不存在,所以你就会看到预期的错误。
要解决这个问题,你可以告诉Python通过shell来运行这个命令,只需要在Popen里加上shell=True
:
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
,没有达到你想要的效果。