Como você chama um comando externo (como se eu o tivesse digitado no shell do Unix ou no prompt de comando do Windows) de dentro de um script Python?
4886
Veja o módulo de subprocessos na biblioteca padrão:
import subprocess
subprocess.run(["ls", "-l"])
A vantagem de subprocess
vs. system
é que é mais flexível (você pode obter o stdout
, stderr
, o "real" código de status, melhor tratamento de erros, etc ...).
A documentação oficial recomenda o subprocess
módulo sobre a alternativa os.system()
:
O
subprocess
módulo fornece instalações mais poderosas para gerar novos processos e recuperar seus resultados; usar esse módulo é preferível a usar esta função [os.system()
].
A seção Substituindo funções mais antigas pelo módulo de subprocesso na subprocess
documentação pode conter algumas receitas úteis.
Para versões do Python anteriores à 3.5, use call
:
import subprocess
subprocess.call(["ls", "-l"])
echo $PATH
usandocall(["echo", "$PATH"])
, mas apenas ecoou a string literal em$PATH
vez de fazer qualquer substituição. Eu sei que poderia obter a variável de ambiente PATH, mas estou pensando se existe uma maneira fácil de fazer com que o comando se comporte exatamente como se eu o tivesse executado no bash.shell=True
para que isso funcione.shell=True
, para esse fim, o Python vem com os.path.expandvars . No seu caso, você pode escrever:os.path.expandvars("$PATH")
. @SethMMorton por favor, reconsidere o seu comentário -> Por que não usar shell = Truefor
loop, como faço sem bloquear meu script python? Eu não me importo com a saída do comando, só quero executar muitos deles.subprocess
quandoshell=False
, useshlex.split
uma maneira fácil de fazer isso docs.python.org/2/library/shlex.html#shlex.splitAqui está um resumo das maneiras de chamar programas externos e as vantagens e desvantagens de cada um:
os.system("some_command with args")
passa o comando e os argumentos para o shell do seu sistema. Isso é bom porque você pode realmente executar vários comandos ao mesmo tempo dessa maneira e configurar canais e redirecionamento de entrada / saída. Por exemplo:Entretanto, embora isso seja conveniente, você deve lidar manualmente com a fuga de caracteres do shell, como espaços, etc. Por outro lado, isso também permite executar comandos que são simplesmente comandos do shell e não programas externos. Veja a documentação .
stream = os.popen("some_command with args")
fará o mesmo queos.system
exceto, oferecendo um objeto semelhante a um arquivo que você pode usar para acessar a entrada / saída padrão para esse processo. Existem três outras variantes de popen que tratam a E / S um pouco diferente. Se você passa tudo como uma string, seu comando é passado para o shell; se você as passar como uma lista, não precisará se preocupar com nada. Veja a documentação .A
Popen
classe dosubprocess
módulo. Isso pretende substituir,os.popen
mas tem a desvantagem de ser um pouco mais complicado por ser tão abrangente. Por exemplo, você diria:ao invés de:
mas é bom ter todas as opções existentes em uma classe unificada, em vez de 4 funções popen diferentes. Veja a documentação .
A
call
função dosubprocess
módulo. Isso é basicamentePopen
igual à classe e usa todos os mesmos argumentos, mas simplesmente espera até que o comando seja concluído e forneça o código de retorno. Por exemplo:Veja a documentação .
Se você estiver no Python 3.5 ou posterior, poderá usar a nova
subprocess.run
função, que é muito parecida com a acima, mas ainda mais flexível e retorna umCompletedProcess
objeto quando o comando termina a execução.O módulo os também possui todas as funções fork / exec / spawn que você teria em um programa em C, mas não recomendo usá-las diretamente.
O
subprocess
módulo provavelmente deve ser o que você usa.Finalmente, esteja ciente de que, para todos os métodos em que você passa o comando final a ser executado pelo shell como uma string, você é responsável por escapá-lo. Existem sérias implicações de segurança se qualquer parte da string que você passar não puder ser totalmente confiável. Por exemplo, se um usuário estiver inserindo parte / parte da string. Se você não tiver certeza, use esses métodos apenas com constantes. Para lhe dar uma dica das implicações, considere este código:
e imagine que o usuário insira algo "minha mãe não me amava && rm -rf /" que poderia apagar todo o sistema de arquivos.
fonte
open
.subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.runsubprocess.run(..)
, o que exatamente faz "Isso não captura stdout ou stderr por padrão". implica? E osubprocess.check_output(..)
STDERR?echo
na frente da string foi passada paraPopen
? Então o comando completo seráecho my mama didnt love me && rm -rf /
.subprocess.run()
ou de seus irmãos mais velhossubprocess.check_call()
et al. Para os casos em que estes não são suficientes, consultesubprocess.Popen()
.os.popen()
talvez não deva ser mencionado, ou vir mesmo depois de "hackear seu próprio código fork / exec / spawn".Implementação típica:
Você é livre para fazer o que quiser com os
stdout
dados no pipe. Na verdade, você pode simplesmente omitir esses parâmetros (stdout=
estderr=
) e eles se comportarão comoos.system()
.fonte
.readlines()
lê todas as linhas de uma só vez, ou seja, bloqueia até o subprocesso sair (fecha a extremidade do tubo). Para ler em tempo real (se não há problemas de tamponamento) você pode:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(nota: nãos
no final) não veja nenhum dado até que o filho preencha seu buffer. Se a criança não produzir muitos dados, a saída não será em tempo real. Veja o segundo motivo em Q: Por que não usar apenas um cachimbo (popen ())? . Algumas soluções alternativas são fornecidas nesta resposta (pexpect, pty, stdbuf)Popen
tarefas simples. Isso também especifica desnecessariamenteshell=True
. Tente uma dassubprocess.run()
respostas.Algumas dicas sobre como desanexar o processo filho do processo chamado (iniciando o processo filho em segundo plano).
Suponha que você queira iniciar uma tarefa longa a partir de um script CGI. Ou seja, o processo filho deve viver mais que o processo de execução do script CGI.
O exemplo clássico da documentação do módulo de subprocesso é:
A idéia aqui é que você não deseja esperar na linha 'subprocesso de chamada' até que o longtask.py seja concluído. Mas não está claro o que acontece após a linha 'um pouco mais de código aqui' do exemplo.
Minha plataforma de destino era o FreeBSD, mas o desenvolvimento estava no Windows, então eu enfrentei o problema no Windows primeiro.
No Windows (Windows XP), o processo pai não será concluído até que o longtask.py termine seu trabalho. Não é o que você deseja em um script CGI. O problema não é específico para o Python; na comunidade PHP, os problemas são os mesmos.
A solução é passar o sinalizador de criação de processo DETACHED_PROCESS para a função CreateProcess subjacente na API do Windows. Se você instalou o pywin32, pode importar o sinalizador do módulo win32process, caso contrário, você mesmo deve defini-lo:
/ * UPD 2015.10.27 @eryksun em um comentário abaixo observa que o sinalizador semanticamente correto é CREATE_NEW_CONSOLE (0x00000010) * /
No FreeBSD, temos outro problema: quando o processo pai termina, ele também termina os processos filhos. E isso também não é o que você deseja em um script CGI. Algumas experiências mostraram que o problema parecia estar no compartilhamento de sys.stdout. E a solução de trabalho foi a seguinte:
Não verifiquei o código em outras plataformas e não sei os motivos do comportamento no FreeBSD. Se alguém souber, compartilhe suas idéias. O Google ao iniciar processos em segundo plano no Python ainda não esclarece.
fonte
DETACHED_PROCESS
nacreationflags
evita este, impedindo a criança de herdar ou a criação de um console. Se você deseja um novo console, useCREATE_NEW_CONSOLE
(0x00000010).os.devnull
porque alguns programas de console saem com um erro caso contrário. Crie um novo console quando desejar que o processo filho interaja com o usuário simultaneamente com o processo pai. Seria confuso tentar fazer as duas coisas em uma única janela.Observe que isso é perigoso, pois o comando não é limpo. Deixo para você procurar no Google a documentação relevante nos módulos 'os' e 'sys'. Existem várias funções (exec * e spawn *) que farão coisas semelhantes.
fonte
subprocess
como uma solução um pouco mais versátil e portátil. A execução de comandos externos é, naturalmente, inerentemente não portável (é necessário garantir que o comando esteja disponível em todas as arquiteturas que você precisa oferecer suporte) e a entrada do usuário como um comando externo é inerentemente insegura.Eu recomendo usar o subprocesso módulo vez do os.system, pois ele faz o escape para você e, portanto, é muito mais seguro.
fonte
subprocess
quandoshell=False
, useshlex.split
uma maneira fácil de fazer isso docs.python.org/2/library/shlex.html#shlex.split ( que é a maneira recomendada de acordo com o docs docs.python.org/2/library/subprocess.html#popen-constructor )Se você deseja retornar os resultados do comando, pode usar
os.popen
. No entanto, isso foi preterido desde a versão 2.6 em favor do módulo de subprocessos , que outras respostas abordaram bem.fonte
Existem muitas bibliotecas diferentes que permitem chamar comandos externos com o Python. Para cada biblioteca, dei uma descrição e mostrei um exemplo de como chamar um comando externo. O comando que usei como exemplo é
ls -l
(liste todos os arquivos). Se você quiser descobrir mais sobre qualquer uma das bibliotecas que listei e vinculei a documentação de cada uma delas.Espero que isso ajude você a tomar uma decisão sobre qual biblioteca usar :)
O subprocesso permite chamar comandos externos e conectá-los aos respectivos canais de entrada / saída / erro (stdin, stdout e stderr). Subprocesso é a opção padrão para executar comandos, mas às vezes outros módulos são melhores.
os é usado para "funcionalidade dependente do sistema operacional". Também pode ser usado para chamar comandos externos com
os.system
eos.popen
(Nota: Também existe um subprocess.popen). o OS sempre rodará o shell e é uma alternativa simples para pessoas que não precisam ou não sabem como usá-losubprocess.run
.sh é uma interface de subprocesso que permite chamar programas como se fossem funções. Isso é útil se você deseja executar um comando várias vezes.
O plumbum é uma biblioteca para programas Python "do tipo script". Você pode chamar programas como funções como em
sh
. O plumbum é útil se você deseja executar um pipeline sem o shell.O pexpect permite gerar aplicativos filhos, controlá-los e encontrar padrões em suas saídas. Esta é uma alternativa melhor ao subprocesso para comandos que esperam um tty no Unix.
fabric é uma biblioteca Python 2.5 e 2.7. Permite executar comandos de shell local e remoto. O Fabric é uma alternativa simples para executar comandos em um shell seguro (SSH)
O enviado é conhecido como "subprocesso para humanos". É usado como um invólucro de conveniência em torno do
subprocess
módulo.commands
contém funções de wrapper paraos.popen
, mas foi removido do Python 3 porsubprocess
ser uma alternativa melhor.A edição foi baseada no comentário de JF Sebastian.
fonte
Eu sempre uso
fabric
para coisas como:Mas isso parece ser uma boa ferramenta:
sh
(interface de subprocesso do Python) .Veja um exemplo:
fonte
Verifique a biblioteca Python "pexpect" também.
Permite o controle interativo de programas / comandos externos, mesmo ssh, ftp, telnet, etc. Você pode digitar algo como:
fonte
Com a biblioteca padrão
Use o módulo de subprocesso (Python 3):
É a maneira padrão recomendada. No entanto, tarefas mais complicadas (canais, saída, entrada etc.) podem ser entediantes de construir e escrever.
Nota sobre a versão do Python: Se você ainda estiver usando o Python 2, o subprocess.call funcionará de maneira semelhante.
ProTip: shlex.split pode ajudá-lo a analisar o comando para
run
,call
e outrassubprocess
funções, caso você não queira (ou não possa!) Fornecê-las em forma de lista:Com dependências externas
Se você não se importa com dependências externas, use plumbum :
É o melhor
subprocess
invólucro. É multiplataforma, ou seja, funciona em sistemas Windows e Unix. Instale porpip install plumbum
.Outra biblioteca popular é sh :
No entanto,
sh
diminuiu o suporte do Windows, por isso não é tão impressionante como costumava ser. Instale porpip install sh
.fonte
Se você precisar da saída do comando que está chamando, poderá usar subprocess.check_output (Python 2.7+).
Observe também o parâmetro shell .
fonte
check_output
requer uma lista em vez de uma string. Se você não depende de espaços entre aspas para validar sua chamada, a maneira mais simples e legível de fazer isso ésubprocess.check_output("ls -l /dev/null".split())
.É assim que eu executo meus comandos. Esse código tem tudo o que você precisa
fonte
Atualizar:
subprocess.run
é a abordagem recomendada no Python 3.5 se o seu código não precisar manter a compatibilidade com versões anteriores do Python. É mais consistente e oferece facilidade de uso semelhante ao Envoy. (A tubulação não é tão simples assim. Veja esta pergunta para saber como .)Aqui estão alguns exemplos da documentação .
Execute um processo:
Aumentar na execução com falha:
Captura de saída:
Resposta original:
Eu recomendo tentar Envoy . É um invólucro para subprocesso, que, por sua vez, visa substituir os módulos e funções mais antigos. O enviado é subprocesso para humanos.
Exemplo de uso do README :
Tubo de material também:
fonte
Usar subprocesso .
... ou para um comando muito simples:
fonte
os.system
está bem, mas meio datado. Também não é muito seguro. Em vez disso, tentesubprocess
.subprocess
não chama sh diretamente e, portanto, é mais seguro do queos.system
.Obtenha mais informações aqui .
fonte
subprocess
não remova todos os problemas de segurança e tenha alguns problemas incômodos.Simples, use
subprocess.run
, que retorna umCompletedProcess
objeto:Por quê?
A partir do Python 3.5, a documentação recomenda subprocess.run :
Aqui está um exemplo do uso mais simples possível - e é exatamente o que é solicitado:
run
espera que o comando seja concluído com êxito e retorna umCompletedProcess
objeto. Em vez disso, pode aumentarTimeoutExpired
(se vocêtimeout=
argumentar) ouCalledProcessError
(se falhar e você for aprovadocheck=True
).Como você pode deduzir do exemplo acima, stdout e stderr são direcionados para o seu próprio stdout e stderr por padrão.
Podemos inspecionar o objeto retornado e ver o comando que foi dado e o código de retorno:
Capturando saída
Se você deseja capturar a saída, pode passar
subprocess.PIPE
para o apropriadostderr
oustdout
:(Acho interessante e um pouco contra-intuitivo que as informações da versão sejam colocadas no stderr em vez de no stdout.)
Passe uma lista de comandos
Pode-se passar facilmente de fornecer manualmente uma sequência de comandos (como a pergunta sugere) para fornecer uma sequência construída programaticamente. Não crie cadeias programaticamente. Este é um possível problema de segurança. É melhor supor que você não confia na entrada.
Observe que somente
args
deve ser passado posicionalmente.Assinatura completa
Aqui está a assinatura real na fonte e como mostrado por
help(run)
:O
popenargs
ekwargs
são dadas para oPopen
construtor.input
pode ser uma sequência de bytes (ou unicode, se especificar codificação ouuniversal_newlines=True
) que serão canalizados para o stdin do subprocesso.A documentação descreve
timeout=
echeck=True
melhor do que eu poderia:e este exemplo para
check=True
é melhor do que um que eu poderia inventar:Assinatura expandida
Aqui está uma assinatura expandida, conforme fornecido na documentação:
Observe que isso indica que apenas a lista args deve ser passada posicionalmente. Portanto, passe os argumentos restantes como argumentos de palavras-chave.
Popen
Quando usar em
Popen
vez disso? Eu lutaria para encontrar casos de uso baseados apenas nos argumentos. O uso direto dePopen
, no entanto, daria acesso a seus métodos, incluindopoll
'send_signal', 'terminate' e 'wait'.Aqui está a
Popen
assinatura, conforme fornecida na fonte . Eu acho que esse é o encapsulamento mais preciso das informações (ao contrário dehelp(Popen)
):Mas mais informativa é a
Popen
documentação :A compreensão da documentação restante
Popen
será deixada como um exercício para o leitor.fonte
shell=True
ou (melhor ainda) passar o comando como uma lista.Há também Plumbum
fonte
Usar:
os - Este módulo fornece uma maneira portátil de usar a funcionalidade dependente do sistema operacional.
Para mais
os
funções, aqui está a documentação.fonte
Pode ser assim simples:
fonte
os.system
recomenda explicitamente evitá-lo em favor desubprocess
.Eu gosto bastante do shell_command por sua simplicidade. Ele é construído sobre o módulo de subprocesso.
Aqui está um exemplo da documentação:
fonte
Há outra diferença aqui que não é mencionada anteriormente.
subprocess.Popen
executa o <comando> como um subprocesso. No meu caso, preciso executar o arquivo <a> que precisa se comunicar com outro programa, <b>.Eu tentei o subprocesso e a execução foi bem-sucedida. No entanto, <b> não pôde se comunicar com <a>. Tudo é normal quando corro ambos do terminal.
Mais uma: (OBSERVAÇÃO: o kwrite se comporta de maneira diferente de outros aplicativos. Se você tentar o abaixo com o Firefox, os resultados não serão os mesmos.)
Se você tentar
os.system("kwrite")
, o fluxo do programa congela até que o usuário feche o kwrite. Para superar isso, tenteios.system(konsole -e kwrite)
. Esse programa continuou fluindo, mas o kwrite se tornou o subprocesso do console.Qualquer pessoa que executa o kwrite não é um subprocesso (ou seja, no monitor do sistema, ele deve aparecer na extremidade esquerda da árvore).
fonte
os.system
não permite que você armazene resultados; portanto, se você deseja armazenar resultados em alguma lista ou algo assim,subprocess.call
funciona.fonte
subprocess.check_call
é conveniente se você não quiser testar os valores de retorno. Ele lança uma exceção em qualquer erro.fonte
Eu costumo usar o subprocesso junto com o shlex (para lidar com o escape de strings entre aspas):
fonte
Plugue sem vergonha, escrevi uma biblioteca para isso: P https://github.com/houqp/shell.py
É basicamente um invólucro para popen e shlex por enquanto. Ele também suporta comandos de canalização, para que você possa encadear comandos mais facilmente no Python. Então você pode fazer coisas como:
fonte
No Windows, você pode simplesmente importar o
subprocess
módulo e executar comandos externos chamandosubprocess.Popen()
,subprocess.Popen().communicate()
esubprocess.Popen().wait()
como abaixo:Resultado:
fonte
No Linux, caso você queira chamar um comando externo que será executado independentemente (continuará sendo executado após o término do script python), você poderá usar uma fila simples como spooler de tarefas ou o comando at
Um exemplo com o spooler de tarefas:
Notas sobre o spooler de tarefas (
ts
):Você pode definir o número de processos simultâneos a serem executados ("slots") com:
ts -S <number-of-slots>
A instalação
ts
não requer privilégios de administrador. Você pode baixar e compilá-lo da fonte com um simplesmake
, adicioná-lo ao seu caminho e pronto.fonte
ts
não é padrão em nenhuma distro que eu conheça, embora o ponteiro paraat
seja levemente útil. Você provavelmente também deve mencionarbatch
. Como em outros lugares, aos.system()
recomendação provavelmente deve mencionar pelo menossubprocess
a substituição recomendada.Você pode usar o Popen e, em seguida, verificar o status do procedimento:
Confira subprocesso .
fonte
Para buscar a identificação de rede no OpenStack Neutron :
Saída da nova net-list
Saída de impressão (networkId)
fonte
os.popen()
em 2016. O script Awk pode ser facilmente substituído pelo código Python nativo.