Python 启动包含管道命令的子进程时找不到文件错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24306205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 04:25:03  来源:igfitidea点击:

File not found error when launching a subprocess containing piped commands

pythonshellsubprocesspipe

提问by h4ck3d

I need to run the command date | grep -o -w '"+tz+"'' | wc -wusing Python on my localhost. I am using subprocessmodule for the same and using the check_outputmethod as I need to capture the output for the same.

我需要date | grep -o -w '"+tz+"'' | wc -w在我的本地主机上使用 Python运行命令 。我正在使用subprocess相同的模块并使用该check_output方法,因为我需要捕获相同的输出。

However it is throwing me an error :

但是它给我一个错误:

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

采纳答案by Bakuriu

You have to add shell=Trueto execute a shell command. check_outputis trying to find an executable called: date | grep -o -w '"+tz+"'' | wc -wand he cannot find it. (no idea why you removed the essential information from the error message).

您必须添加shell=True才能执行 shell 命令。check_output正试图找到一个名为: 的可执行文件date | grep -o -w '"+tz+"'' | wc -w,但他找不到它。(不知道为什么您从错误消息中删除了基本信息)。

See the difference between:

查看两者之间的区别:

>>> 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'

And:

和:

>>> subprocess.check_output('date | grep 1', shell=True)
b'gio 19 giu 2014, 14.15.35, CEST\n'

Read the documentation about the Frequently Used Argumentsfor more information about the shellargument and how it changes the interpretation of the other arguments.

阅读有关常用参数的文档,了解有关该shell参数以及它如何更改其他参数的解释的更多信息。



Note that you should try to avoid using shell=Truesince spawning a shell can be a security hazard (even if you do not execute untrusted input attacks like Shellshock can still be performed!).

请注意,您应该尽量避免使用,shell=True因为生成 shell 可能存在安全隐患(即使您不执行像 Shellshock 这样的不受信任的输入攻击,仍然可以执行!)。

The documentation for the subprocess module has a little section about replacing the shell pipeline. You can do so by spawning the two processes in python and use subprocess.PIPE:

subprocess 模块的文档中有一小部分是关于替换 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]

You can write some simple wrapper function to easily define pipelines:

您可以编写一些简单的包装函数来轻松定义管道:

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

With this in place you can write pipeline('date | grep 1')or pipeline('date', 'grep 1')or pipeline(['date'], ['grep', '1'])

有了这个,你可以写pipeline('date | grep 1')pipeline('date', 'grep 1')pipeline(['date'], ['grep', '1'])

回答by mightypile

The most common cause of FileNotFound with subprocess, in my experience, is the use of spaces in your command. Use a list, instead.

根据我的经验,带有子进程的 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"])

This change results in no more FileNotFound errors, and is a nice solution if you got here searching for that exception with a simpler command. If you are using python 3.5 or greater, try using this approach:

此更改不再导致 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'))

You should see how one command's output becomes another's input just like using a shell pipe, but you can easily debug each step of the process in python. Using subprocess.runis recommended for python > 3.5, but not available in prior versions.

您应该会看到一个命令的输出如何变成另一个命令的输入,就像使用 shell 管道一样,但是您可以在 python 中轻松调试该过程的每个步骤。python > 3.5 建议使用subprocess.run,但在以前的版本中不可用。