Como usar o comando `subprocess` com pipes

Respostas:

438

Para usar um tubo com o subprocessmódulo, você precisa passar shell=True.

No entanto, isso não é realmente aconselhável por várias razões, entre as quais a segurança. Em vez disso, crie os processos pse grepseparadamente e canalize a saída de um para o outro, da seguinte maneira:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

No seu caso particular, no entanto, a solução simples é chamar subprocess.check_output(('ps', '-A'))e, str.findem seguida, a saída.

Taymon
fonte
81
1 para separar a saída / entrada para evitar o uso deshell=True
Nicolas
5
Não se esqueça, erro subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1significa apenas que nada foi encontrado pelo grep, portanto é um comportamento normal.
Serge
2
Por que precisamos do ps.wait()para quando já temos a saída. ps.wait.__doc__aguarda a criança para terminar, mas o conteúdo da criança parece já colocado na outputvariável
Papouche Guinslyzinho
3
@ MakisH Você está vendo string.find, que foi preterido em favor de str.find(ou seja, o método findnos strobjetos).
Taymon 16/10/2015
4
nota: se grepmorrer prematuramente; pspode travar indefinidamente se produzir saída suficiente para preencher seu buffer de canal do SO (porque você não chamou ps.stdout.close()o pai). Troque a ordem de partida, para evitá-la #
jfs 22/03
54

Ou você sempre pode usar o método de comunicação nos objetos do subprocesso.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

O método de comunicação retorna uma tupla da saída padrão e do erro padrão.

jkalivas
fonte
3
Eu acho que usar communicateé melhor que wait. Existe um aviso: "Isso entra em conflito ao usar stdout = PIPE e / ou stderr = PIPE, e o processo filho gera saída suficiente para um canal, de forma que ele bloqueia a espera do buffer do canal do SO para aceitar mais dados. evite isso. "
Paolo
2
Para esclarecer o comentário de Paolo acima, o aviso é para esperar, não para se comunicar - ou seja, é o motivo pelo qual ele diz que se comunicar é melhor.
EnemyBagJones
23

Consulte a documentação sobre a configuração de um pipeline usando o subprocesso: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Não testei o seguinte exemplo de código, mas deve ser aproximadamente o que você deseja:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
AlcubierreDrive
fonte
2
Aquando do check isto falhou, veja a resposta abaixo por Taymon por algo que funciona sem perder tempo
Alvin
2
O subprocess.check_output parece não existir no Python 2.6.9 #
RightmireM
6

A solução JKALAVIS é boa, no entanto, eu acrescentaria uma melhoria para usar o shlex em vez de SHELL = TRUE. abaixo im grepping out Query times

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
Daniel Smith
fonte
1
Por que shellx sobre shell?
AFP_555
2
Onde o shlex é usado aqui?
3lokh
4

Além disso, tente usar o 'pgrep'comando em vez de'ps -A | grep 'process_name'

Shooe
fonte
2
se você quiser obter o ID do processo, obviamente
Shooe
3

Você pode experimentar a funcionalidade de canal no sh.py :

import sh
print sh.grep(sh.ps("-ax"), "process_name")
amoffat
fonte
0

Após o Python 3.5, você também pode usar:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

A execução do comando está bloqueando e a saída estará em process.stdout .

zingi
fonte