2013-11-01 4 views
3

Я пытаюсь написать утилиту, которая будет бесшовно передавать неограниченное количество команд вместе в Python. Это то, что я придумал до сих пор, после the documentation on piping in subprocess:Решение цепочки процессов в Python

from subprocess import Popen, PIPE, STDOUT 

def taskchain(argset, result=STDOUT): 
    lastprocess = None 

    for index, args in enumerate(argset): # expected to be a list containing lists 
     process = Popen(args, stdout=stdout if index == (len(argset)-1) else PIPE, 
      stdin=None if lastprocess is None else lastprocess.stdout) 

     if lastprocess is not None: 
      lastprocess.stdout.close() 

     lastprocess = process 

    if stdout == PIPE: 
     return lastprocess.communicate()[0] 
    else: 
     lastprocess.wait() 

Обратите внимание, что я не использую shell=True для того, чтобы мы надеемся избежать проблем безопасности там.

К сожалению, это не работает, так как я получаю:

OSError: [Errno 9] Baf file descriptor 

Я не уверен, что, кажется, терпит неудачу. Может ли кто-нибудь помочь мне написать метод для реализации цепочки процессов для неограниченного количества подпроцессов?

(Используйте случай, как это:. taskchain([('ps', 'aux'), ('grep', 'python'), ('cut', '-b', '1')]))

+0

Стиль примечание: в 'argset.index (аргументы)' что-то * * Я действительно не могу смотреть ... это больно! Если вы перебираете простой «argset», то вы * не должны * нуждаться в информации об индексе. Если вы только заботитесь об этом, используйте «for i in range» (len (argset)): «вместо этого. Если вам нужны оба (как в вашем случае), то вы * должны * использовать 'enumerate' !!! Обратите внимание, что 'argset.index' может возвращать неверный индекс, если есть равные элементы, потому что' перечислять' всегда возвращает правильный индекс текущих 'args'. – Bakuriu

+0

Рефакторинг соответственно. –

+1

Вы видели ['plumbum'] (http://plumbum.readthedocs.org/en/latest/) или [' sh'] (http://amoffat.github.io/sh/)? Это * не *, чтобы препятствовать вам, просто чтобы вы знали, что пакеты существуют. – jfs

ответ

0

С помощью @ ecatmur в выше, вот окончательное решение:

def taskchain(*args, **kwargs): 
    output = kwargs.get('output', PIPE) 
    error_output = kwargs.get('error_output', STDOUT) 
    lastprocess = None 

    for index, argset in enumerate(args): 
     islastprocess = index == len(args) - 1 

     process = Popen(argset, stdout=output if islastprocess else PIPE, 
       stdin=None if lastprocess is None else lastprocess.stdout, 
       stderr=error_output) 

     if lastprocess is not None: 
      lastprocess.stdout.close() 

     lastprocess = process 

    if output == PIPE: 
     return lastprocess.communicate() 
    else: 
     lastprocess.wait() 

Процессы прикованы вместе, эффективно эмулирует оболочки на основе трубопровода без рисков безопасности!

Примеры:

>>> print taskchain(('ps','aux'), ('grep','python'), ('cut','-c','1-50'))[0].trim() 
naftuli 3221 0.1 0.1 60960 12376 pts/3 S+ 
naftuli 3242 0.0 0.0 32592 5748 pts/2 S+ 
naftuli 3246 0.0 0.0 9388 916 pts/2 S+ 
naftuli 5852 0.0 0.2 430284 20200 ?  Sl 
root  8153 0.0 0.1 95520 11060 ?  S 

>>> print taskchain(('ls',), ('grep', 'ic'))[0] 
Music 
Pictures 
Public 
2
stdout=stdout if argset.index(args) == (len(args) - 1) else PIPE) 

Это, вероятно, следует

stdout=stdout if argset.index(args) == (len(argset) - 1) else PIPE) 

А вы бы лучше использовать enumerate, а не argset.index.

Кроме того, вам необходимо подключить подпроцессы друг к другу:

..., stdin=None if lastprocess is None else lastprocess.stdout) 

Наконец, STDOUT действует только в качестве аргумента для параметра stderr; чтобы пройти stdout через вас, вы должны пройти stdout=None.

+0

Я все еще вижу ту же ошибку, я обновлю свой вопрос с помощью текущего кода. –

+0

@NaftuliTzviKay это ваше использование 'STDIN' - обновлено выше. – ecatmur

+0

Не уверен, что вы подразумеваете под STDIN. Пример в документации Python делает это так же, как и в настоящее время. Можете ли вы продемонстрировать, что вы имеете в виду, исправив его? Логика имеет смысл для меня: если это последний процесс, перенаправляйте вывод туда, где указывает пользователь, иначе отправьте его в PIPE. –

Смежные вопросы