Se eu fizer o seguinte:
import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
Eu recebo:
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'
Aparentemente, um objeto cStringIO.StringIO não fica quack perto o suficiente de um arquivo duck para se adequar ao subprocesso.Popen. Como faço para resolver isso?
python
subprocess
stdin
Daryl Spitzer
fonte
fonte
call(['ls', '-1'], shell=True)
está incorreto. Eu recomendo ler perguntas comuns da descrição da tag do subprocesso . Em particular, por que o subprocess.Popen não funciona quando args é uma sequência? explica por quecall(['ls', '-1'], shell=True)
está errado. Lembro-me de deixar comentários sob a postagem do blog, mas não os vejo agora por algum motivo.subprocess.run
consulte stackoverflow.com/questions/48752152/…Respostas:
Popen.communicate()
documentação:Portanto, seu exemplo pode ser escrito da seguinte maneira:
Na versão atual do Python 3, você pode usar
subprocess.run
para passar a entrada como uma string para um comando externo e obter seu status de saída e sua saída como uma string de volta em uma chamada:fonte
Eu descobri esta solução alternativa:
Existe um melhor?
fonte
stdin.write()
uso é desencorajado,p.communicate()
deve ser usado. Veja minha resposta.communicate
ele fecha o canal e permite que o processo termine normalmente.read()
com isso,communicate()
mesmo sem argumentos).Estou um pouco surpreso que ninguém tenha sugerido a criação de um pipe, que é, na minha opinião, a maneira mais simples de passar uma string para o stdin de um subprocesso:
fonte
os
easubprocess
documentação ambos concordam que você deve preferir o segundo sobre o primeiro. Esta é uma solução herdada que possui uma substituição padrão (um pouco menos concisa); a resposta aceita cita a documentação pertinente.Existe uma solução bonita se você estiver usando o Python 3.4 ou melhor. Use o
input
argumento em vez dostdin
argumento, que aceita um argumento de bytes:Isso funciona para
check_output
erun
, mas nãocall
oucheck_call
por algum motivo.fonte
check_output
ter uminput
argumento, mas nãocall
.check_call
mas funciona pararun
. Também funciona com input = string, desde que você passe um argumento de codificação também de acordo com a documentação.Estou usando python3 e descobri que você precisa codificar sua string antes de poder passá-la para o stdin:
fonte
b'something'
). Ele retornará err e out como bytes também. Se você quiser evitar isso, pode passaruniversal_newlines=True
paraPopen
. Então ele aceitará a entrada como str e retornará err / out como str também.universal_newlines=True
também converterá suas novas linhas para que correspondam ao seu sistema #Receio que não. O canal é um conceito de SO de baixo nível, portanto, requer absolutamente um objeto de arquivo representado por um descritor de arquivo no nível de SO. Sua solução alternativa é a correta.
fonte
fonte
Cuidado que
Popen.communicate(input=s)
pode causar problemas ses
for muito grande, porque aparentemente o processo pai o armazenará em buffer antes de bifurcar o subprocesso filho, o que significa que ele precisa "duas vezes mais" de memória usada naquele momento (pelo menos de acordo com a explicação "por baixo do capô" e documentação vinculada encontrada aqui ). No meu caso em particular,s
havia um gerador que foi expandido completamente e somente depois gravado parastdin
que o processo pai fosse imenso logo antes do nascimento da criança e não restasse memória para bifurcar: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
fonte
fonte
shell=True
é tão comumente usado sem um bom motivo, e esta é uma pergunta popular, deixe-me salientar que há muitas situações em quePopen(['cmd', 'with', 'args'])
é decididamente melhor doPopen('cmd with args', shell=True)
que o shell dividir o comando e os argumentos em tokens, mas não fornecendo nada útil, ao adicionar uma quantidade significativa de complexidade e, assim, também atacar a superfície.fonte
No Python 3.7+, faça o seguinte:
e você provavelmente desejará adicionar
capture_output=True
para obter a saída da execução do comando como uma string.Nas versões mais antigas do Python, substitua
text=True
poruniversal_newlines=True
:fonte