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?
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:
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"])
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 = True
for
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
quando shell=False
, use shlex.split
uma maneira fácil de fazer isso docs.python.org/2/library/shlex.html#shlex.split
Aqui 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:
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 .
stream = os.popen("some_command with args")
fará o mesmo que os.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 do subprocess
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:
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 .
A call
função do subprocess
módulo. Isso é basicamente Popen
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:
return_code = subprocess.call("echo Hello World", shell=True)
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 um CompletedProcess
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:
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.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
subprocess.run(..)
, o que exatamente faz "Isso não captura stdout ou stderr por padrão". implica? E o subprocess.check_output(..)
STDERR?
echo
na frente da string foi passada para Popen
? Então o comando completo será echo my mama didnt love me && rm -rf /
.
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".
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 stdout
dados no pipe. Na verdade, você pode simplesmente omitir esses parâmetros ( stdout=
e stderr=
) e eles se comportarão como os.system()
.
.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ão s
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 desnecessariamente shell=True
. Tente uma das subprocess.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 é:
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.
DETACHED_PROCESS
na creationflags
evita 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).
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.
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.
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.
subprocess.call(['ping', 'localhost'])
subprocess
quando shell=False
, use shlex.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 )
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.
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.system
e 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 subprocess
módulo.
r = envoy.run("ls -l") # Run command
r.std_out # get output
comandos
commands
contém funções de wrapper para os.popen
, mas foi removido do Python 3 por subprocess
ser uma alternativa melhor.
A edição foi baseada no comentário de JF Sebastian.
Eu sempre uso fabric
para 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)
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')
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
, call
e outras subprocess
funçõ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'))
Se você não se importa com dependências externas, use plumbum :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
É o melhor subprocess
invó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, sh
diminuiu o suporte do Windows, por isso não é tão impressionante como costumava ser. Instale por pip install sh
.
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()
, eshutil
).
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
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()
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')
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'>]
os.system
está bem, mas meio datado. Também não é muito seguro. Em vez disso, tente subprocess
. subprocess
não chama sh diretamente e, portanto, é mais seguro do queos.system
.
Obtenha mais informações aqui .
subprocess
não remova todos os problemas de segurança e tenha alguns problemas incômodos.
Chamando um comando externo em Python
Simples, use subprocess.run
, que retorna um CompletedProcess
objeto:
>>> 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)
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)
run
espera que o comando seja concluído com êxito e retorna um CompletedProcess
objeto. 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
Se você deseja capturar a saída, pode passar subprocess.PIPE
para o apropriado stderr
ou 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.)
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 args
deve ser passado posicionalmente.
Aqui está a assinatura real na fonte e como mostrado por help(run)
:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
O popenargs
e kwargs
são dadas para o Popen
construtor. input
pode 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=True
melhor 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
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.
Quando usar em Popen
vez 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 Popen
assinatura, 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 Popen
documentaçã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 Popen
será deixada como um exercício para o leitor.
shell=True
ou (melhor ainda) passar o comando como uma lista.
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
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 os
funções, aqui está a documentação.
Pode ser assim simples:
import os
cmd = "your command"
os.system(cmd)
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
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, 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).
os.system
não permite que você armazene resultados; portanto, se você deseja armazenar resultados em alguma lista ou algo assim, subprocess.call
funciona.
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)
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}'"
No Windows, você pode simplesmente importar o subprocess
mó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
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
):
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 simples make
, adicioná-lo ao seu caminho e pronto.
ts
não é padrão em nenhuma distro que eu conheça, embora o ponteiro para at
seja levemente útil. Você provavelmente também deve mencionar batch
. Como em outros lugares, a os.system()
recomendação provavelmente deve mencionar pelo menos subprocess
a substituição recomendada.
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 .
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
os.popen()
em 2016. O script Awk pode ser facilmente substituído pelo código Python nativo.
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.