命令
$ find ~/foo/ -type f -iname "*.txt" -print0 | parallel -0 cat
用途GNU 并行打印.txt
下的所有文件~/foo/
。
我有一个 python 脚本,我想在其中调用这个 bash 命令:
import subprocess, sys
def runBashCommand(my_command):
process = subprocess.Popen(my_command.split(), stdout=subprocess.PIPE)
output = process.communicate()[0]
return None
def makeCommand(my_path):
return "find {} -type f -iname \"*.txt\" -print0 | parallel -0 cat".format(my_path)
发行
>>> makeCommand('~/foo/')
回报
'find ~/foo/ -type f -iname "*.txt" -print0 | parallel -0 cat'
但发出
>>> runBashCommand(makeCommand('~/foo/'))
产生错误
find: paths must precede expression: |
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
我的脚本有什么问题?
答案1
您实际上并没有运行bash
命令。您正在做的是直接运行可执行文件并传递参数。
尝试以下脚本看看发生了什么:
import subprocess
p = subprocess.Popen(["echo", "a", "b", "|", "rev"], stdout=subprocess.PIPE)
print p.communicate()
输出将是:
('a b | rev\n', None)
没有发生重定向,“|”正在逐字传递。即,就好像您输入了find ... \| parallel ...
。因此出现错误。
有两种方法可以修复它。
最简单的方法:传递
shell=True
到subprocess.Popen
.这将通过 shell 运行它,以及所有需要的东西。如果这样做,您还需要传入一个字符串而不是数组:import subprocess p = subprocess.Popen("echo a b | rev", stdout=subprocess.PIPE, shell=True) print p.communicate() # Result: ('b a\n', None)
如果你这样做,对字符串中的参数替换要非常小心。
稳健的方法:使用 Python 打开两个进程并将它们通过管道连接在一起。
import subprocess # First command p1 = subprocess.Popen(["echo", "a", "b"], stdout=subprocess.PIPE) # Second command's input linked to the first one's output p2 = subprocess.Popen(["rev"], stdin=p1.stdout, stdout=subprocess.PIPE) # Read from p2 to get the output print p2.communicate() # Result: ('b a\n', None)
这更加健壮,并且不会产生额外的 shell,但另一方面它的打字量也更大。如果你这样做,注意不发生外壳替换。在你的情况下,它看起来不像你需要它,但如果你想使用,比如说
~
,你必须通过Python(例如os.getenv("HOME")
)来获取它。
答案2
您不能split()
使用命令字符串,因为它包含需要由 shell 处理的字符,例如~
和|
。使用版本:
process = subprocess.Popen(my_command, stdout=subprocess.PIPE, shell=True)