我试图调用一个名为foo的可执行文件,并传递一些命令行参数。外部脚本调用可执行文件并使用以下命令:
./main/foo --config config_file 2>&1 | /usr/bin/tee temp.log
该脚本使用Popen执行此命令,如下所示:
from subprocess import Popen
from subprocess import PIPE
def run_command(command, returnObject=False):
cmd = command.split(' ')
print('%s' % cmd)
p = None
print('command : %s' % command)
if returnObject:
p = Popen(cmd)
else:
p = Popen(cmd)
p.communicate()
print('returncode: %s' % p.returncode)
return p.returncode
return p
command = "./main/foo --config config_file 2>&1 | /usr/bin/tee temp.log
"
run_command(command)
然而,这传递了额外的论据[' 2>& 1',' |',' / usr / bin / tee',&#39 ; temp.log']到foo可执行文件。
如何在保持功能的同时摆脱传递给foo的额外参数? 我已经尝试过shell = True但是为了安全起见(shell注入攻击),请阅读有关避免它的内容。寻找一个简洁的解决方案。
由于
更新: - 按照tee命令
更新了文件答案 0 :(得分:3)
字符串
./main/foo --config config_file 2>&1 | /usr/bin/tee >temp.log
...充满了shell结构。 如果没有正在使用的shell,这些对任何事都没有意义。因此,您有两种选择:
shell=True
例如,2>&1
与将stderr=subprocess.STDOUT
传递给Popen
是一回事,而你的三通 - 因为它的输出被重定向并且没有传递任何参数 - 只能被替换与stdout=open('temp.log', 'w')
。
因此:
p = subprocess.Popen(['./main/foo', '--config', 'config_file'],
stderr=subprocess.STDOUT,
stdout=open('temp.log', 'w'))
...或者,如果你真的 想要tee
命令,但只是错误地使用它(也就是说,如果你想要tee temp.log
,而不是{{ 1}}):
tee >temp.log
在函数中包含它,并检查两端的成功可能如下所示:
p1 = subprocess.Popen(['./main/foo', '--config', 'config_file'],
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE)
p2 = subprocess.Popen(['tee', 'temp.log'], stdin=p1.stdout)
p1.stdout.close() # drop our own handle so p2's stdin is the only handle on p1.stdout
stdout, _ = p2.communicate()
顺便说一下 - 如果你想使用def run():
p1 = subprocess.Popen(['./main/foo', '--config', 'config_file'],
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE)
p2 = subprocess.Popen(['tee', 'temp.log'], stdin=p1.stdout)
p1.stdout.close() # drop our own handle so p2's stdin is the only handle on p1.stdout
# True if both processes were successful, False otherwise
return (p2.wait() == 0 && p1.wait() == 0)
并返回shell=True
的退出状态,而不是foo
,事情会变得更有趣。请考虑以下事项:
tee
... p = subprocess.Popen(['bash', '-c', 'set -o pipefail; ' + command_str])
bash扩展将强制shell退出,第一个管道组件的状态失败(如果没有组件失败,则为0),而不是仅使用最终组件的退出状态
答案 1 :(得分:1)
除了the explanation from @Charles Duffy answer之外,还有一些“简洁”的代码示例。
在Python中运行shell命令:
#!/usr/bin/env python
from subprocess import check_call
check_call("./main/foo --config config_file 2>&1 | /usr/bin/tee temp.log",
shell=True)
没有shell:
#!/usr/bin/env python
from subprocess import Popen, PIPE, STDOUT
tee = Popen(["/usr/bin/tee", "temp.log"], stdin=PIPE)
foo = Popen("./main/foo --config config_file".split(),
stdout=tee.stdin, stderr=STDOUT)
pipestatus = [foo.wait(), tee.wait()]
注意:请勿将"command arg".split()
与非文字字符串一起使用。
请参阅How do I use subprocess.Popen to connect multiple processes by pipes?
答案 2 :(得分:0)
您可以将两个StackOverflow问题的答案组合在一起:
1. piping together several subprocesses
x | y
问题
2. Merging a Python script's subprocess' stdout and stderr (while keeping them distinguishable)
2>&1
问题