команды канала проверки ошибок, сделанные в python для unix

Я компилирую команду для выполнения в системе unix из python, содержащую несколько шагов конвейера. например.:

grep foo myfile | cmd1 | cmd2 > output

Они соответствуют ряду преобразований записей, в которых есть foo из myfile. Иногда я создаю его как команду, которую должен выполнить os.system, а в других случаях использую модуль subprocess.

Как я могу выполнить проверку ошибок в каждой части канала из Python? Например в 99% случаев foo записей в myfile а остальные пайпы работают. Но если по какой-то причине myfile существует, но не содержит записей foo, то остальная часть конвейера разрывается, потому что вы передаете пустые файлы, а оставшиеся команды требуют для работы непустых входных данных. Это затрудняет отладку, потому что все, что вы видите, это вывод сломанной трубы, не зная, какой промежуточный шаг не удался.

Есть ли способ построить каналы в Python, которые проверяют ошибки на промежуточных этапах? Например. проверить, что часть канала grep действительно содержит некоторый вывод, что вывод cmd1 на вводе grep также содержит некоторый вывод и так далее? Спасибо.


person Community    schedule 17.12.2012    source источник
comment
Самый простой способ сделать это — сделать что-то изначально в Python. Вызовы туда и обратно из ОС и Python просто вводят дополнительные переменные и сложности, которых обычно лучше избегать в первую очередь.   -  person Silas Ray    schedule 17.12.2012
comment
Итак, как бы вы сделали это в Python, если для этого требуется вызов внешней команды? Единственный способ, который я знаю, это subprocess. Я не могу переписать все команды, которые я вызываю в Python   -  person    schedule 17.12.2012
comment
В bash у вас есть переменная PIPESTATUS — используйте ее, если можете. В противном случае просто сделайте это на питоне, как предложил sr2222 - настройте каналы, запустите программы с перенаправленным вводом-выводом, проверьте их статус выхода, в чем проблема? Упомянутый вами модуль даже принимает stdin/stdout/stderr в качестве параметров!   -  person loreb    schedule 18.12.2012


Ответы (3)


Вот мой подход, проверенный на Python 2.6 Linux.

а. Определите метод

def run_command(command):
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p.communicate()
    return (p.returncode, out, err)

б. Используйте его следующим образом

def test_run_command_pipestatus(self):
    # the exit $PIPESTATUS is the return code of "exit 2". The default return code is the return code of last command in the pipe
    return_code, out, err = run_command("exit 2 | tail -n 1; exit $PIPESTATUS")
    print "return_code = %d" %return_code
    print out
    print err
    self.assertEqual(2, return_code)
person Mingjiang Shi    schedule 08.01.2014

В основном то же, что и ответ Минцзян Ши, который содержит в основном всю необходимую ключевую информацию, но без дополнительных функций и устранения проблемы. (и протестировано в Python 2.7.12 и 3.5.2)

$PIPESTATUS не существует в sh, поэтому вы должны установить для исполняемого файла bash, если в вашем дистрибутиве нет /bin/sh, который действует как bash (например, Ubuntu, который использует dash). И это массив, поэтому я предпочитаю использовать его как единое целое.

И я рекомендую wait() вместо communicate(), чтобы вы могли фильтровать вместо slurp (используйте при чтении в небольшой буфер вместо загрузки всего вывода в память перед обработкой).

Итак, все, что вам нужно сделать, это:

  • следует использовать строку, а не список аргументов
  • использовать оболочку = True
  • используйте исполняемый файл = "/bin/bash"

код:

p = subprocess.Popen("false | true; exit ${PIPESTATUS[0]}", shell=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# at this point you do your filtering, eg. using p.stdout.readinto(buf)

p.wait()
if p.returncode != 0:
    # handle it here
person Peter    schedule 26.11.2016

это мой подход, независимо от того, сколько команд mutch pipe. это сумма всех кодов состояния и выход с результатом echo 1 |echo 2 или cat test |echo 2 замените вашими командами

››getstatusoutput('status=0;echo 1 |echo 2;for ((i=0;i‹${#PIPESTATUS[*]};i++));do let status=${status}+${PIPESTATUS[ ${i}]};готово;выход из $status')

(0, '2')

›› getstatusoutput('status=0;cat test |echo 2;for ((i=0;i‹${#PIPESTATUS[*]};i++));do let status=${status}+${PIPESTATUS[ ${i}]};готово;выход из $status')

(1, '2\ncat: test: Нет такого файла или каталога')

person uitb    schedule 20.11.2020