Если я сделаю следующее:
import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
Я получил:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__
(p2cread, p2cwrite,
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles
p2cread = stdin.fileno()
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'
По-видимому, объект cStringIO.StringIO не крякает достаточно близко к файловой утке, чтобы удовлетворить subprocess.Popen. Как мне обойти это?
python
subprocess
stdin
Дэрил Спитцер
источник
источник
call(['ls', '-1'], shell=True)
неверно. Вместо этого я рекомендую прочитать общие вопросы из описания тегов подпроцесса . В частности, почему subprocess.Popen не работает, когда args является последовательностью? объясняет почемуcall(['ls', '-1'], shell=True)
не так. Я помню, как оставлял комментарии под постом в блоге, но я почему-то их сейчас не вижу.subprocess.run
см. Stackoverflow.com/questions/48752152/…Ответы:
Popen.communicate()
документация:Итак, ваш пример может быть записан следующим образом:
В текущей версии Python 3 вы можете использовать
subprocess.run
, чтобы передать ввод как строку во внешнюю команду и получить ее статус завершения , а ее вывод как строку обратно за один вызов:источник
Я понял этот обходной путь:
Есть ли лучший?
источник
stdin.write()
использование не рекомендуется,p.communicate()
следует использовать. Смотри мой ответ.communicate
он закроет канал и позволит процессу завершиться изящно.read()
, какcommunicate()
и без аргументов).Я немного удивлен, что никто не предложил создать канал, который, на мой взгляд, является самым простым способом передачи строки в стандартный поток подпроцесса:
источник
os
Иsubprocess
документации оба согласны с тем , что вы должны отдавать предпочтение последней над первой. Это устаревшее решение, которое имеет (чуть менее лаконичную) стандартную замену; Принятый ответ цитирует соответствующую документацию.Есть прекрасное решение, если вы используете Python 3.4 или выше. Используйте
input
аргумент вместоstdin
аргумента, который принимает аргумент байтов:Это работает для
check_output
иrun
, но неcall
илиcheck_call
по какой-то причине.источник
check_output
должен бытьinput
аргумент, но нетcall
.check_call
но это работает дляrun
. Он также работает с input = string, если вы передаете аргумент кодирования в соответствии с документацией.Я использую python3 и обнаружил, что вам нужно закодировать вашу строку, прежде чем вы сможете передать ее в стандартный ввод:
источник
b'something'
). Он также будет возвращать ошибки и байты. Если вы хотите избежать этого, вы можете перейтиuniversal_newlines=True
кPopen
. Затем он примет ввод как str и вернет err / out как str.universal_newlines=True
также преобразует ваши новые строки в соответствии с вашей системойБоюсь, что нет. Канал представляет собой низкоуровневую концепцию ОС, поэтому ему абсолютно необходим файловый объект, представленный дескриптором файла на уровне ОС. Ваш обходной путь правильный.
источник
источник
Остерегайтесь, это
Popen.communicate(input=s)
может доставить вам неприятности, еслиs
оно слишком велико, потому что, очевидно, родительский процесс будет буферизовать его до разветвления дочернего подпроцесса, что означает, что ему требуется «вдвое больше» используемой памяти на тот момент (по крайней мере, в соответствии с объяснением «под капотом») и связанная документация найдена здесь ). В моем конкретном случаеs
был генератор, который сначала был полностью развернут и только потом записан,stdin
так что родительский процесс был огромным прямо перед порождением потомка, и не осталось памяти для его разветвления:File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory
источник
источник
shell=True
это обычно используется без веской причины, и это популярный вопрос, позвольте мне отметить, что есть много ситуаций, когдаPopen(['cmd', 'with', 'args'])
решительно лучше, чемPopen('cmd with args', shell=True)
когда оболочка разбивает команду и аргументы на токены, но не предоставляет ничего другого полезно, при этом добавляя значительное количество сложности и, следовательно, также поверхность атаки.источник
На Python 3.7+ сделайте это:
и вы, вероятно, захотите добавить,
capture_output=True
чтобы получить результат выполнения команды в виде строки.В старых версиях Python замените
text=True
наuniversal_newlines=True
:источник