Estou tentando escrever um script de wrapper para um programa de linha de comando (svnadmin Verifique) que exibirá um bom indicador de progresso para a operação. Isso exige que eu seja capaz de ver cada linha de saída do programa empacotado assim que for lançada.
Imaginei que apenas executaria o programa usando subprocess.Popen
, use stdout=PIPE
e depois leria cada linha conforme ela chegasse e atuaria de acordo. No entanto, quando executei o código a seguir, a saída parecia estar armazenada em buffer em algum lugar, fazendo com que aparecesse em dois blocos, linhas 1 a 332 e depois 333 a 439 (a última linha de saída)
from subprocess import Popen, PIPE, STDOUT
p = Popen('svnadmin verify /var/svn/repos/config', stdout = PIPE,
stderr = STDOUT, shell = True)
for line in p.stdout:
print line.replace('\n', '')
Depois de examinar um pouco a documentação do subprocesso, descobri o bufsize
parâmetroPopen
, então tentei definir o bufsize como 1 (buffer cada linha) e 0 (sem buffer), mas nenhum valor parecia mudar a maneira como as linhas estavam sendo entregues.
Nesse ponto, eu estava começando a procurar por canudos, então escrevi o seguinte loop de saída:
while True:
try:
print p.stdout.next().replace('\n', '')
except StopIteration:
break
mas obteve o mesmo resultado.
É possível obter a saída do programa 'em tempo real' de um programa executado usando subprocesso? Existe alguma outra opção no Python que seja compatível com a frente (não exec*
)?
fonte
sydout=PIPE
gravação para que o subprocesso grave diretamente no console, ignorando o processo pai?Respostas:
Eu tentei isso e, por algum motivo, enquanto o código
buffers agressivamente, a variante
não. Aparentemente, este é um bug conhecido: http://bugs.python.org/issue3907 (o problema agora está "fechado" em 29 de agosto de 2018)
fonte
while p.poll() is None
em vez dewhile True
, e remover oif not line
print(line.decode('utf-8').rstrip())
.PYTHONUNBUFFERED=1
. Isto é especialmente útil para as saídas que são infinitafonte
p.stdout.close()
não está claro.Você pode direcionar a saída do subprocesso para os fluxos diretamente. Exemplo simplificado:
fonte
.communicate()
? Ou o conteúdo é perdido para os fluxos stderr / stdout pai?communicate()
método retornadoCompletedProcess
. Além disso,capture_output
é mutuamente exclusivo comstdout
estderr
.Você pode tentar isso:
Se você usar a linha de leitura em vez da leitura, haverá alguns casos em que a mensagem de entrada não será impressa. Experimente com um comando que requer uma entrada embutida e veja por si mesmo.
fonte
O subprocesso de streaming stdin e stdout com assíncio na postagem do blog em Python por Kevin McCarthy mostra como fazer isso com asyncio:
fonte
import nest_asyncio; nest_asyncio.apply()
e usar o comando shell, ou seja, emprocess = await create_subprocess_shell(*command, stdout=PIPE, stderr=PIPE, shell=True)
vez deprocess = await create_subprocess_exec(...)
. Felicidades!Problema de saída em tempo real resolvido: Encontrei um problema semelhante no Python, enquanto capturava a saída em tempo real do programa c. Eu adicionei " fflush (stdout) ;" no meu código C. Funcionou para mim. Aqui está o snip do código
<< Programa C >>
<< Programa Python >>
<< SAÍDA >> Impressão: Contagem 1 Impressão: Contagem 2 Impressão: Contagem 3
Espero que ajude.
~ sairam
fonte
flush(stdout)
) em C ++. Obrigado!Encontrei o mesmo problema há algum tempo. Minha solução foi abandonar a iteração para o
read
método, que retornará imediatamente, mesmo que seu subprocesso não termine a execução, etc.fonte
Dependendo do caso de uso, também convém desativar o buffer no próprio subprocesso.
Se o subprocesso for um processo Python, você poderá fazer isso antes da chamada:
Ou, alternativamente, passe isso no
env
argumento paraPopen
.Caso contrário, se você estiver no Linux / Unix, poderá usar a
stdbuf
ferramenta. Por exemplo, como:Veja também aqui sobre
stdbuf
ou outras opções.(Veja também aqui a mesma resposta.)
fonte
Usei esta solução para obter saída em tempo real em um subprocesso. Esse loop será interrompido assim que o processo for concluído, sem a necessidade de uma declaração de interrupção ou possível loop infinito.
fonte
if out=='': break
depoisout = sub_process...
Encontrei esta função "plug-and-play" aqui . Trabalhou como um encanto!
fonte
stderr=subprocess.STDOUT
realmente ajuda muito na captura de dados de streaming. Eu estou votando.Você pode usar um iterador sobre cada byte na saída do subprocesso. Isso permite a atualização embutida (as linhas que terminam com '\ r' substituem a linha de saída anterior) do subprocesso:
fonte
No Python 3.x, o processo pode travar porque a saída é uma matriz de bytes em vez de uma sequência de caracteres. Certifique-se de decodificá-lo em uma string.
A partir do Python 3.6, você pode fazer isso usando o parâmetro
encoding
no Popen Constructor . O exemplo completo:Observe que esse código redirecionamentos
stderr
parastdout
e manipula erros de saída .fonte
O uso do pexpect [ http://www.noah.org/wiki/Pexpect ] com linhas de leitura sem bloqueio resolverá esse problema. Isso decorre do fato de que os pipes são armazenados em buffer e, portanto, a saída do aplicativo é armazenada em buffer pelo pipe; portanto, você não pode chegar a essa saída até que o buffer seja preenchido ou o processo morra.
fonte
Solução completa:
fonte
universal_newlines=True
aPopen()
ligação, provavelmente não precisa colocar seu próprio tratamento também - esse é o objetivo da opção.Este é o esqueleto básico que eu sempre uso para isso. Isso facilita a implementação de tempos limites e é capaz de lidar com processos de interrupção inevitáveis.
fonte
(Esta solução foi testada com o Python 2.7.15)
Você só precisa do sys.stdout.flush () após cada linha de leitura / gravação:
fonte
Poucas respostas sugerindo python 3.x ou pthon 2.x, o código abaixo funcionará para ambos.
fonte