Ошибка при обнаружении файла при запуске подпроцесса

Мне нужно запустить команду date | grep -o -w '"+tz+"'' | wc -w с помощью Python на моем localhost. Я использую модуль 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

Ответы

Ответ 1

Вы должны добавить 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 и используя subprocess.PIPE:

date_proc = subprocess.Popen(['date'], stdout=subprocess.PIPE)
grep_proc = subprocess.check(['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'])