h4c*_*k3d 36 python shell subprocess pipe
我需要date | grep -o -w '"+tz+"'' | wc -w在我的localhost上使用Python 运行命令 .我正在使用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
Run Code Online (Sandbox Code Playgroud)
请帮助我哪里出错了.我是python的新手
Bak*_*riu 70
您必须添加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'
Run Code Online (Sandbox Code Playgroud)
和:
>>> subprocess.check_output('date | grep 1', shell=True)
b'gio 19 giu 2014, 14.15.35, CEST\n'
Run Code Online (Sandbox Code Playgroud)
阅读有关常用参数的文档,以获取有关参数的更多信息shell以及它如何更改其他参数的解释.
请注意,您应该尽量避免使用,shell=True因为产生shell可能会带来安全隐患(即使您不执行像Shellshock那样的不受信任的输入攻击仍然可以执行!).
子进程模块的文档有一些关于替换shell管道的部分.你可以通过在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]
Run Code Online (Sandbox Code Playgroud)
您可以编写一些简单的包装函数来轻松定义管道:
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
Run Code Online (Sandbox Code Playgroud)
有了这个,你可以写pipeline('date | grep 1')或pipeline('date', 'grep 1')或pipeline(['date'], ['grep', '1'])
tri*_*eee 10
发生这种FileNotFoundError情况是因为 - 在没有shell=True- Python 尝试找到一个文件名是您传入的整个字符串的可执行文件。您需要添加shell=True以使 shell 解析并执行该字符串,或者弄清楚如何重新表达该命令行以避免需要外壳。
顺便说一句,这里的 shell 编程确实很奇怪。在任何正常的系统上,date绝对不会输出"+tz+",因此其余的处理是没有意义的。
此外,使用wc -w来计算输出单词的数量grep是不常见的。更常见的用例(如果您不能简单地用于grep -c计算匹配行数)是用于wc -l计算grep.
无论如何,如果可以的话,你想避免shell=True;如果此处的目的是测试该date命令,您可能应该用本机 Python 代码替换 shell 脚本的其余部分。
优点:
date),而不需要类 Unix 平台。缺点:
"+tz+"排除了这一点,如果目的只是计算的输出中出现的次数date,请尝试
p = subprocess.run(['date'],
capture_output=True, text=True,
check=True)
result = len(p.stdout.split('"+tz+"'))-1
Run Code Online (Sandbox Code Playgroud)
关键字参数text=True需要Python 3.7;为了兼容早期的 Python 版本,请尝试(用词不当)旧同义词universal_newlines=True。对于非常旧的 Python 版本,可能会回退到subprocess.check_output().
-w如果您确实需要选项的语义grep,则需要检查与匹配项相邻的字符是否不是字母字符,并排除那些字符。我将其作为练习,实际上会假设此处的原始 shell 脚本实现实际上并不正确。(也许可以尝试一下re.split(r'(?<=^|\W)"\+tz\+"(?=\W|$)', p.stdout)。)
在更简单的情况下(单个命令、无管道、通配符、重定向、shell 内置命令等),您可以使用 Pythonshlex.split()将命令解析为正确引用的参数列表。例如,
>>> import shlex
>>> shlex.split(r'''one "two three" four\ five 'six seven' eight"'"nine'"'ten''')
['one', 'two three', 'four five', 'six seven', 'eight\'nine"ten']
Run Code Online (Sandbox Code Playgroud)
请注意,常规字符串split()在这里完全不合适;它只是在每个空白字符上进行分割,并且不支持任何类型的引用或转义。(但还要注意如何shlex.split愚蠢地从原始输入中返回一个标记列表:
>>> shlex.split('''date | grep -o -w '"+tz+"' | wc -w''')
['date', '|', 'grep', '-o', '-w', '"+tz+"', '|', 'wc', '-w']
Run Code Online (Sandbox Code Playgroud)
(更重要的是,这并不完全是原始输入,它后面有一个多余的额外单引号'"+tz+"')。
如果您要将其传递给subprocess.run,它实际上是将等作为参数传递|给grep,date而不是实现 shell 管道!你仍然必须明白你在做什么。)
以我的经验,使用子进程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"])
Run Code Online (Sandbox Code Playgroud)
此更改不会再导致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'))
Run Code Online (Sandbox Code Playgroud)
您应该像使用shell管道一样看到一个命令的输出如何变成另一个命令的输入,但是您可以轻松地在python中调试过程的每一步。对于python> 3.5,建议使用subprocess.run,但在以前的版本中不可用。
| 归档时间: |
|
| 查看次数: |
41335 次 |
| 最近记录: |