2013-08-09 2 views
1

у меня есть это, но подпроцесс чтения из трубы в конце нависает:питон подпроцесс повесить на чтение трубы

$cat waitforinput.sh 
#!/bin/sh 


while read line 
do 
echo $line 
done      


>>> p1 = subprocess.Popen(["/home/abc/waitforinput.sh", "-v"], shell=True, executable=None,stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
>>> 
>>> 
>>> p1.stdin.write('This is a good idea\n') 
>>> p1.stdin.write('This is a good idea\n') 
>>> p1.stdin.write('This is a good idea\n') 
>>> p1.stdin.write('This is a good idea\n') 
>>> p1.stdin.write('This is a good idea\n') 
>>> 
>>> 
>>> p1.stdin.flush() 
>>> 
>>> for i in p1.stdout: 
...  print i 
... 

Что я должен сделать так, чтобы она не висит?

ответ

3

Вместо флеша(), звоните p1.stdin.close().

... 
p1.stdin.write('This is good idea\n') 
p1.stdin.write('This is good idea\n') 

p1.stdin.close() 

for i in p1.stdout: 
    print i 

ОБНОВЛЕНИЕ

Заменить stdout-iteration с в то время как контур с stdout.readline()

см Python Manpage -u часть:

Силы STDIN, STDOUT и STDERR быть полностью небуферизованным. В системах , где это имеет значение, также ставьте stdin, stdout и stderr в двоичном режиме . Обратите внимание: внутри xread- строк(), readlines() и итераторов файловых объектов есть внутренняя буферизация («для строки в sys.stdin»), на которую не влияет эта опция. Для работы вокруг этого вы захотите использовать «sys.stdin.readline()» внутри a «while 1:» loop.

p1.stdin.flush() 

while True: 
    line = p1.stdout.readline() 
    if not line: 
     break 
    print line 

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

+0

Это сработало. Благодарю. Еще два вопроса: 1. Почему 'flush()' не работает? 2. И почему аргумент «-v», казалось, не имел никакого эффекта? – abc

+0

@abc, ваш скрипт оболочки не обрабатывает аргумент командной строки. – falsetru

+1

@abc. Насколько я знаю, буфер не сбрасывается до тех пор, пока не будет достигнут размер трубы. (Проверьте размер трубы в 'ulimit -a') – falsetru

1

Проблема в том, что waitforinput.sh выполняет буферизацию своего вывода. Решение falsetru работает, потому что закрытие приводит к тому, что сценарий выходит из него, и он очищает выходные буферы. Это обычный способ обработки конвейерных команд.

Если вы хотите получить результат в интерактивном режиме, вы можете использовать модуль pty или pexpect, чтобы обмануть сценарий, подумав, что он пишет терминал. Затем его выход будет только буферизироваться по строке.

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