web-dev-qa-db-ja.com

パイプコマンドを含むサブプロセスを起動すると、ファイルが見つからないというエラーが発生する

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が初めてです

33
h4ck3d

シェルコマンドを実行するには_Shell=True_を追加する必要があります。 _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'
_

Shell引数の詳細および他の引数の解釈の変更方法については、 よく使用される引数 に関するドキュメントを参照してください。


_Shell=True_の使用は避けなければならないことに注意してください。シェルの生成はセキュリティ上の危険になる可能性があるためです(Shellshockのような信頼できない入力攻撃を実行しなくても実行できます!)。

サブプロセスモジュールのドキュメントには、 シェルパイプラインの置き換え に関する小さなセクションがあります。そのためには、pythonで2つのプロセスを生成し、_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'])を記述できます。

68
Bakuriu

私の経験では、サブプロセスでの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'))

シェルパイプを使用するのと同じように、1つのコマンドの出力が別のコマンドの入力になる様子を確認する必要がありますが、Pythonでプロセスの各ステップを簡単にデバッグできます。 python> 3.5には subprocess.run を使用することをお勧めしますが、以前のバージョンでは使用できません。

5
mightypile