我需要在我的localhost上使用Python运行命令date | grep -o -w '"+tz+"'' | wc -w
。我正在使用subprocess
模块,并使用check_output
方法,因为我需要捕获相同的输出。
但是它给我一个错误:
Traceback (most recent call last):
File "test.py", line 47, in <module>
check_timezone()
File "test.py", line 40, in check_timezone
count = subprocess.check_output(command)
File "/usr/lib/python2.7/subprocess.py", line 537, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
raise child_exception-
OSError: [Errno 2] No such file or directory
请帮助我哪里出错了。我是python的新手
您必须添加shell=True
才能执行shell命令。 check_output
正试图找到一个名为:date | grep -o -w '"+tz+"'' | wc -w
的可执行文件,但他无法找到它。 (不知道为什么你从错误信息中删除了基本信息)。
看看之间的区别:
>>> subprocess.check_output('date | grep 1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/subprocess.py", line 603, in check_output
with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
File "/usr/lib/python3.4/subprocess.py", line 848, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.4/subprocess.py", line 1446, in _execute_child
raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'date | grep 1'
和:
>>> subprocess.check_output('date | grep 1', shell=True)
b'gio 19 giu 2014, 14.15.35, CEST\n'
阅读有关Frequently Used Arguments的文档,了解有关shell
参数及其如何更改其他参数解释的更多信息。
请注意,您应该尽量避免使用shell=True
,因为生成shell可能会带来安全隐患(即使您不执行不受信任的输入攻击,仍然可以执行Shellshock!)。
子进程模块的文档有一些关于replacing the shell pipeline的部分。您可以通过在python中生成两个进程并使用subprocess.PIPE
来实现:
date_proc = subprocess.Popen(['date'], stdout=subprocess.PIPE)
grep_proc = subprocess.check_output(['grep', '1'], stdin=date_proc.stdout, stdout=subprocess.PIPE)
date_proc.stdout.close()
output = grep_proc.communicate()[0]
您可以编写一些简单的包装函数来轻松定义管道:
import subprocess
from shlex import split
from collections import namedtuple
from functools import reduce
proc_output = namedtuple('proc_output', 'stdout stderr')
def pipeline(starter_command, *commands):
if not commands:
try:
starter_command, *commands = starter_command.split('|')
except AttributeError:
pass
starter_command = _parse(starter_command)
starter = subprocess.Popen(starter_command, stdout=subprocess.PIPE)
last_proc = reduce(_create_pipe, map(_parse, commands), starter)
return proc_output(*last_proc.communicate())
def _create_pipe(previous, command):
proc = subprocess.Popen(command, stdin=previous.stdout, stdout=subprocess.PIPE)
previous.stdout.close()
return proc
def _parse(cmd):
try:
return split(cmd)
except Exception:
return cmd
有了这个,你可以写pipeline('date | grep 1')
或pipeline('date', 'grep 1')
或pipeline(['date'], ['grep', '1'])
根据我的经验,FileNotFound与子进程的最常见原因是在命令中使用空格。请改用列表。
# Wrong, even with a valid command string
subprocess.run(["date | grep -o -w '\"+tz+\"' | wc -w"])
# Fixed
subprocess.run(["date", "|", "grep", "-o", "-w", "'\"+tz+\"'", "|", "wc", "-w"])
此更改不会导致FileNotFound错误,并且如果您使用更简单的命令搜索此异常,这是一个很好的解决方案。如果您使用的是python 3.5或更高版本,请尝试使用此方法:
import subprocess
a = subprocess.run(["date"], stdout=subprocess.PIPE)
print(a.stdout.decode('utf-8'))
b = subprocess.run(["grep", "-o", "-w", "'\"+tz+\"'"],
input=a.stdout, stdout=subprocess.PIPE)
print(b.stdout.decode('utf-8'))
c = subprocess.run(["wc", "-w"],
input=b.stdout, stdout=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
您应该看到一个命令的输出如何成为另一个输入,就像使用shell管道一样,但是您可以在python中轻松调试该过程的每个步骤。对于python> 3.5,建议使用subprocess.run,但在以前的版本中不可用。