Chamando um comando externo do Python


4886

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?

Respostas:


4696

Veja o módulo de subprocessos na biblioteca padrão:

import subprocess
subprocess.run(["ls", "-l"])

A vantagem de subprocessvs. 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 subprocessmódulo sobre a alternativa os.system():

O subprocessmó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 subprocessdocumentação pode conter algumas receitas úteis.

Para versões do Python anteriores à 3.5, use call:

import subprocess
subprocess.call(["ls", "-l"])

Existe uma maneira de usar a substituição de variável? IE eu tentei fazer isso echo $PATHusando call(["echo", "$PATH"]), mas apenas ecoou a string literal em $PATHvez 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.
Kevin Wheeler

@KevinWheeler Você precisará usar shell=Truepara que isso funcione.
SethMMorton 02/09/2015

39
@KevinWheeler Você NÃO deve usar 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 = True
Murmel

a chamada bloqueia? ou seja, se eu quiser executar vários comandos em um forloop, como faço sem bloquear meu script python? Eu não me importo com a saída do comando, só quero executar muitos deles.
Charlie Parker

5
Se você deseja criar uma lista a partir de um comando com parâmetros , uma lista que pode ser usada com subprocessquando shell=False, use shlex.splituma maneira fácil de fazer isso docs.python.org/2/library/shlex.html#shlex.split
Daniel F

2985

Aqui está um resumo das maneiras de chamar programas externos e as vantagens e desvantagens de cada um:

  1. 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:

    os.system("some_command < input_file | another_command > output_file")  

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 .

  1. stream = os.popen("some_command with args")fará o mesmo que os.systemexceto, 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 .

  2. A Popenclasse do subprocessmódulo. Isso pretende substituir, os.popenmas tem a desvantagem de ser um pouco mais complicado por ser tão abrangente. Por exemplo, você diria:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    ao invés de:

    print os.popen("echo Hello World").read()

    mas é bom ter todas as opções existentes em uma classe unificada, em vez de 4 funções popen diferentes. Veja a documentação .

  3. A callfunção do subprocessmódulo. Isso é basicamente Popenigual à 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:

    return_code = subprocess.call("echo Hello World", shell=True)  

    Veja a documentação .

  4. Se você estiver no Python 3.5 ou posterior, poderá usar a nova subprocess.runfunção, que é muito parecida com a acima, mas ainda mais flexível e retorna um CompletedProcessobjeto quando o comando termina a execução.

  5. 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 subprocessmó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:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

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.


22
Boa resposta / explicação. Como essa resposta justifica o lema do Python, conforme descrito neste artigo? fastcompany.com/3026446/… "Estilisticamente, Perl e Python têm filosofias diferentes. O lema mais conhecido de Perl é" Existe mais de uma maneira de fazê-lo ". Python foi projetado para ter uma maneira óbvia de fazê-lo" Parece que deveria ser o outro jeito! No Perl, conheço apenas duas maneiras de executar um comando - usando back-tick ou open.
Jean

12
Se você estiver usando o Python 3.5+, use subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run
phoenix

4
O que normalmente é necessário saber é o que é feito com o STDOUT e o STDERR do processo filho, porque se eles forem ignorados, sob algumas condições (bastante comuns), eventualmente o processo filho emitirá uma chamada de sistema para gravar no STDOUT (STDERR também?) isso excederia o buffer de saída fornecido para o processo pelo SO, e o SO fará com que ele seja bloqueado até que algum processo seja lido nesse buffer. Portanto, com as formas atualmente recomendadas subprocess.run(..), o que exatamente faz "Isso não captura stdout ou stderr por padrão". implica? E o subprocess.check_output(..)STDERR?
Evgeni Sergeev

2
@ Pitto yes, mas não é isso que é executado pelo exemplo. Observe que echona frente da string foi passada para Popen? Então o comando completo será echo my mama didnt love me && rm -rf /.
22718 Chris Arndt

6
Este é sem dúvida o caminho errado. A maioria das pessoas só precisa subprocess.run()ou de seus irmãos mais velhos subprocess.check_call()et al. Para os casos em que estes não são suficientes, consulte subprocess.Popen(). os.popen()talvez não deva ser mencionado, ou vir mesmo depois de "hackear seu próprio código fork / exec / spawn".
Tripleee

358

Implementação típica:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

Você é livre para fazer o que quiser com os stdoutdados no pipe. Na verdade, você pode simplesmente omitir esses parâmetros ( stdout=e stderr=) e eles se comportarão como os.system().


44
.readlines()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,
JFS

1
Você poderia elaborar o que quer dizer com "se não houver problemas de buffer"? Se o processo bloquear definitivamente, a chamada de subprocesso também será bloqueada. O mesmo poderia acontecer com o meu exemplo original. O que mais poderia acontecer com relação ao buffer?
EmmEff

15
o processo filho pode usar buffer de bloco no modo não interativo em vez de buffer de linha, para que p.stdout.readline()(nota: não sno 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)
jfs

4
a questão buffer só importa se você quiser a saída em tempo real, e não se aplica ao seu código que não imprime nada até que todos os dados são recebidos
JFS

3
Essa resposta foi boa no momento, mas não devemos mais recomendar Popentarefas simples. Isso também especifica desnecessariamente shell=True. Tente uma das subprocess.run()respostas.
Tripleee

230

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 é:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

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:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * 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:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

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.


notei uma possível "peculiaridade" com o desenvolvimento de aplicativos py2exe no pydev + eclipse. pude dizer que o script principal não foi desanexado porque a janela de saída do eclipse não estava terminando; mesmo se o script for executado até a conclusão, ele ainda estará aguardando retornos. mas, quando tentei compilar em um executável py2exe, ocorre o comportamento esperado (executa os processos como desanexados e sai). Não tenho certeza, mas o nome do executável não está mais na lista de processos. Isso funciona para todas as abordagens (os.system ( "start *"), os.spawnl com os.P_DETACH, subprocs, etc.)
maranas

1
você também pode precisar do sinalizador CREATE_NEW_PROCESS_GROUP. Veja Popen à espera de processo filho, mesmo quando o filho imediato tiver encerrado
jfs

5
O seguinte está incorreto: "[o] n windows (win xp), o processo pai não será concluído até que o longtask.py termine seu trabalho". O pai sairá normalmente, mas a janela do console (instância conhost.exe) fecha somente quando o último processo anexado é encerrado, e o filho pode ter herdado o console do pai. Definir DETACHED_PROCESSna creationflagsevita este, impedindo a criança de herdar ou a criação de um console. Se você deseja um novo console, use CREATE_NEW_CONSOLE(0x00000010).
Eryk Sun

1
Não quis dizer que a execução como um processo desanexado está incorreta. Dito isso, pode ser necessário definir os identificadores padrão para arquivos, tubulações ou os.devnullporque 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.
Eryk Sun

1
não existe uma maneira independente de sistema operacional de executar o processo em segundo plano?
Charlie Parker

152
import os
os.system("your command")

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.


6
Não faço ideia do que eu quis dizer há quase uma década (verifique a data!), Mas se eu tivesse que adivinhar, seria que não há validação feita.
Nimish

1
Agora, isso deve apontar subprocesscomo 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.
Tripleee

1
Observe o carimbo de data e hora desse cara: a resposta "correta" tem 40x os votos e é a resposta nº 1.
Nimish

A única solução que funcionou para mim na execução de coisas do NodeJS.
Nikolay Shindarov 29/10/19

148

Eu recomendo usar o subprocesso módulo vez do os.system, pois ele faz o escape para você e, portanto, é muito mais seguro.

subprocess.call(['ping', 'localhost'])

Se você deseja criar uma lista com base em um comando com parâmetros , uma lista que pode ser usada com subprocessquando shell=False, use shlex.splituma 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 )
Daniel F

6
Isso está incorreto: " faz o shell escapar para você e, portanto, é muito mais seguro ". O subprocesso não faz escape do shell, o subprocesso não passa seu comando pelo shell, portanto, não há necessidade de escape do shell.
Lie Ryan

144
import os
cmd = 'ls -al'
os.system(cmd)

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.


10
O popen foi descontinuado em favor do subprocesso .
Fox Wilson

Você também pode salvar seu resultado com a chamada os.system, uma vez que funciona como o próprio shell UNIX, como por exemplo os.system ('ls -l> test2.txt')
Stefan Gruenwald

97

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.

Fontes:

Estas são todas as bibliotecas:

Espero que isso ajude você a tomar uma decisão sobre qual biblioteca usar :)

subprocesso

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.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

os é usado para "funcionalidade dependente do sistema operacional". Também pode ser usado para chamar comandos externos com os.systeme os.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á-lo subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

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.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

prumo

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.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

esperar

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.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

tecido

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)

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

enviado

O enviado é conhecido como "subprocesso para humanos". É usado como um invólucro de conveniência em torno do subprocessmódulo.

r = envoy.run("ls -l") # Run command
r.std_out # get output

comandos

commandscontém funções de wrapper para os.popen, mas foi removido do Python 3 por subprocessser uma alternativa melhor.

A edição foi baseada no comentário de JF Sebastian.


74

Eu sempre uso fabricpara coisas como:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Mas isso parece ser uma boa ferramenta: sh(interface de subprocesso do Python) .

Veja um exemplo:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

73

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:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

70

Com a biblioteca padrão

Use o módulo de subprocesso (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

É 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, calle outras subprocessfunções, caso você não queira (ou não possa!) Fornecê-las em forma de lista:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Com dependências externas

Se você não se importa com dependências externas, use plumbum :

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

É o melhor subprocessinvólucro. É multiplataforma, ou seja, funciona em sistemas Windows e Unix. Instale por pip install plumbum.

Outra biblioteca popular é sh :

from sh import ifconfig
print(ifconfig('wlan0'))

No entanto, shdiminuiu o suporte do Windows, por isso não é tão impressionante como costumava ser. Instale por pip install sh.


69

Se você precisar da saída do comando que está chamando, poderá usar subprocess.check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Observe também o parâmetro shell .

Se o shell for True, o comando especificado será executado através do shell. Isso pode ser útil se você estiver usando o Python principalmente para o fluxo de controle aprimorado que ele oferece sobre a maioria dos shells do sistema e ainda desejar acesso conveniente a outros recursos do shell, como pipes de shell, curingas de nome de arquivo, expansão de variável de ambiente e expansão de ~ para a casa do usuário diretório. No entanto, nota que o próprio Python oferece implementações de muitos shell-como características (em particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), e shutil).


1
Observe que check_outputrequer 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()).
Bruno Bronosky

56

É assim que eu executo meus comandos. Esse código tem tudo o que você precisa

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

3
Eu acho que é aceitável para comandos codificados, se aumentar a legibilidade.
quer

54

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:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Aumentar na execução com falha:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Captura de saída:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

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 :

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Tubo de material também:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

os.systemestá bem, mas meio datado. Também não é muito seguro. Em vez disso, tente subprocess. subprocessnão chama sh diretamente e, portanto, é mais seguro do queos.system .

Obtenha mais informações aqui .


2
Embora eu concorde com a recomendação geral, subprocessnão remova todos os problemas de segurança e tenha alguns problemas incômodos.
Tripleee

36

Chamando um comando externo em Python

Simples, use subprocess.run, que retorna um CompletedProcessobjeto:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Por quê?

A partir do Python 3.5, a documentação recomenda subprocess.run :

A abordagem recomendada para chamar subprocessos é usar a função run () para todos os casos de uso que ele puder manipular. Para casos de uso mais avançados, a interface do Popen subjacente pode ser usada diretamente.

Aqui está um exemplo do uso mais simples possível - e é exatamente o que é solicitado:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

runespera que o comando seja concluído com êxito e retorna um CompletedProcessobjeto. Em vez disso, pode aumentar TimeoutExpired(se você timeout=argumentar) ou CalledProcessError(se falhar e você for aprovado check=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:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Capturando saída

Se você deseja capturar a saída, pode passar subprocess.PIPEpara o apropriado stderrou stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(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.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Observe que somente argsdeve ser passado posicionalmente.

Assinatura completa

Aqui está a assinatura real na fonte e como mostrado por help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

O popenargse kwargssão dadas para o Popenconstrutor. inputpode ser uma sequência de bytes (ou unicode, se especificar codificação ou universal_newlines=True) que serão canalizados para o stdin do subprocesso.

A documentação descreve timeout=e check=Truemelhor do que eu poderia:

O argumento de tempo limite é passado para Popen.communicate (). Se o tempo limite expirar, o processo filho será eliminado e aguardado. A exceção TimeoutExpired será gerada novamente após o término do processo filho.

Se a verificação for verdadeira e o processo sair com um código de saída diferente de zero, uma exceção CalledProcessError será gerada. Os atributos dessa exceção mantêm os argumentos, o código de saída e stdout e stderr se eles foram capturados.

e este exemplo para check=Trueé melhor do que um que eu poderia inventar:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Assinatura expandida

Aqui está uma assinatura expandida, conforme fornecido na documentação:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

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 Popenvez disso? Eu lutaria para encontrar casos de uso baseados apenas nos argumentos. O uso direto de Popen, no entanto, daria acesso a seus métodos, incluindo poll'send_signal', 'terminate' e 'wait'.

Aqui está a Popenassinatura, conforme fornecida na fonte . Eu acho que esse é o encapsulamento mais preciso das informações (ao contrário de help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Mas mais informativa é a Popendocumentação :

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Execute um programa filho em um novo processo. No POSIX, a classe usa um comportamento semelhante ao os.execvp () para executar o programa filho. No Windows, a classe usa a função Windows CreateProcess (). Os argumentos para Popen são os seguintes.

A compreensão da documentação restante Popenserá deixada como um exercício para o leitor.


Um exemplo simples de uma comunicação de duas vias entre um processo primário e um subprocesso pode ser encontrada aqui: stackoverflow.com/a/52841475/1349673
James Hirschorn

O primeiro exemplo provavelmente deve ter shell=Trueou (melhor ainda) passar o comando como uma lista.
Tripleee

33

Há também Plumbum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

28

Usar:

import os

cmd = 'ls -al'

os.system(cmd)

os - Este módulo fornece uma maneira portátil de usar a funcionalidade dependente do sistema operacional.

Para mais osfunções, aqui está a documentação.


2
também está obsoleto. use subprocess
Corey Goldberg

28

Pode ser assim simples:

import os
cmd = "your command"
os.system(cmd)

1
Isso não aponta as desvantagens, que são explicadas com muito mais detalhes no PEP-324 . A documentação para os.systemrecomenda explicitamente evitá-lo em favor de subprocess.
Tripleee

25

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:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

Há outra diferença aqui que não é mencionada anteriormente.

subprocess.Popenexecuta 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, tentei os.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).


1
O que você quer dizer com "Alguém executa o kwrite que não é um subprocesso" ?
Peter Mortensen

23

os.systemnão permite que você armazene resultados; portanto, se você deseja armazenar resultados em alguma lista ou algo assim, subprocess.callfunciona.


22

subprocess.check_callé conveniente se você não quiser testar os valores de retorno. Ele lança uma exceção em qualquer erro.


22

Eu costumo usar o subprocesso junto com o shlex (para lidar com o escape de strings entre aspas):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

17

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:

ex('echo hello shell.py') | "awk '{print $2}'"

16

No Windows, você pode simplesmente importar o subprocessmódulo e executar comandos externos chamando subprocess.Popen(), subprocess.Popen().communicate()e subprocess.Popen().wait()como abaixo:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Resultado:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

15

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:

import os
os.system('ts <your-command>')

Notas sobre o spooler de tarefas ( ts):

  1. Você pode definir o número de processos simultâneos a serem executados ("slots") com:

    ts -S <number-of-slots>

  2. A instalação tsnão requer privilégios de administrador. Você pode baixar e compilá-lo da fonte com um simples make, adicioná-lo ao seu caminho e pronto.


1
tsnão é padrão em nenhuma distro que eu conheça, embora o ponteiro para atseja levemente útil. Você provavelmente também deve mencionar batch. Como em outros lugares, a os.system()recomendação provavelmente deve mencionar pelo menos subprocessa substituição recomendada.
Tripleee

15

Você pode usar o Popen e, em seguida, verificar o status do procedimento:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Confira subprocesso .


15

Para buscar a identificação de rede no OpenStack Neutron :

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Saída da nova net-list

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Saída de impressão (networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126

Você não deve recomendar os.popen()em 2016. O script Awk pode ser facilmente substituído pelo código Python nativo.
Tripleee
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.