Pergunta

Como posso chamar um comando externo (como se eu tivesse digitado no shell do Unix ou Windows prompt de comando) de dentro de um script Python?

Foi útil?

Solução

Olhe para o subprocess módulo na biblioteca padrão:

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

A vantagem de subprocess vs. sistema é que é mais flexível (você pode obter o stdout, stderr, o "real" código de status, melhor tratamento de erros, etc ...).

O href="https://docs.python.org/library/os.html#os.system" rel="noreferrer"> documentação oficial recomenda a subprocess módulo sobre o os.system alternativa ():

O subprocess módulo fornece instalações mais poderosas para a desova novos processos e recuperar seus resultados; usando esse módulo é preferível usar esta função [ os.system() ].

O " substituir as funções mais velhos com subprocesso seção Módulo " no subprocess documentação pode ter algumas receitas votos.

As versões mais antigas de chamada uso Python:

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

Outras dicas

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 argumentos para shell do seu sistema. Isso é bom porque você pode realmente executar vários comandos de uma vez desta maneira e configurar tubos e redirecionamento de entrada / saída. Por exemplo:

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

    No entanto, enquanto isso é conveniente, você tem que lidar com manualmente a escapar de caracteres shell, como espaços, etc. Por outro lado, isso também permite executar comandos que são simplesmente comandos shell e programas não realmente externas. Consulte a documentação .

  2. stream = os.popen("some_command with args") vai fazer a mesma coisa que os.system exceto que ele dá-lhe um arquivo do tipo de objeto que você pode usar para acesso padrão de entrada / saída para esse processo. Existem 3 outras variantes de Popen que todos pega o i / o de forma ligeiramente diferente. Se você passar tudo como uma corda, em seguida, seu comando é passado para o shell; se você passá-los como uma lista, então você não precisa se preocupar em escapar nada. Consulte a documentação .

  3. A classe Popen do módulo subprocess. Este pretende ser um substituto para os.popen mas tem a desvantagem de ser um pouco mais complicado pelo fato de ser tão abrangente. Por exemplo, você diria:

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

    em vez de:

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

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

  4. A função call do módulo subprocess. Esta é basicamente como a classe Popen e leva todos os mesmos argumentos, mas simplesmente espera até que o comando é concluído e dá-lhe o código de retorno. Por exemplo:

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

    a documentação .

  5. Se você estiver em Python 3.5 ou posterior, você pode usar o novo subprocess.run função "noreferrer", que é muito parecido com o anterior, mas ainda mais flexível e retorna um CompletedProcess objeto quando o comando termina a execução.

  6. O módulo os também tem todos os / exec / funções de desova garfo que você teria em um programa C, mas eu não recomendo usá-los diretamente.

O módulo subprocess provavelmente deve ser o que você usar.

Finalmente lembre-se que para todos os métodos em que você passa o comando final a ser executado pelo shell como uma string e você é responsável por escapar dela. Existem sérias implicações de segurança se qualquer parte da cadeia de caracteres que você passar não pode ser totalmente confiável. Por exemplo, se um usuário está entrando some / qualquer parte da string. Se você está inseguro, use apenas estes métodos com constantes. Para lhe dar uma dica das implicações considerar este código:

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

e imagine que o usuário digita algo "minha mãe não funcionavam amor me && rm-rf /", que poderia apagar todo o sistema de arquivos.

Eu normalmente uso:

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 dados stdout no tubo. Na verdade, você pode simplesmente omitir esses parâmetros (stdout= e stderr=) e ele vai se comportar como os.system().

Algumas dicas sobre destacando o processo filho daquele chamando (de iniciar o processo filho no fundo).

Suponha que você deseja iniciar uma longa tarefa a partir de um CGI-script, que é o processo de criança deve viver mais tempo do que o processo de execução CGI-script.

O exemplo clássico de docs módulo 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 quer esperar na linha 'subprocess chamada' até o longtask.py está terminado. Mas não está claro o que acontece após a linha 'mais algum código aqui' a partir do exemplo.

A minha plataforma de destino foi o FreeBSD, mas o desenvolvimento foi em janelas, então eu enfrentaram o problema no Windows pela primeira vez.

no Windows (Win XP), o processo pai não vai terminar até o longtask.py terminou o seu trabalho. Não é o que você quer em CGI-script. O problema não é específico para Python, na comunidade PHP os problemas são os mesmos.

A solução é passar DETACHED_PROCESS Processo Bandeira Criação para a função CreateProcess subjacente na vitória API. Se acontecer de você ter instalado pywin32 você pode importar a bandeira do módulo win32process, caso contrário, você deve defini-la a si mesmo:

DETACHED_PROCESS = 0x00000008

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

/ * UPD 2015/10/27 @eryksun em um comentário abaixo notas, que a bandeira semanticamente correto é CREATE_NEW_CONSOLE (0x00000010) * /

No FreeBSD nós temos um outro problema: quando o processo pai for concluído, ele termina os processos filhos também. E isso não é o que você quer em CGI-script também. Alguns experimentos mostraram que o problema parecia estar em partilha sys.stdout. E a solução de trabalho foi o seguinte:

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

Eu não tenho verificado o código em outras plataformas e não sei as razões do comportamento no FreeBSD. Se alguém souber, por favor, compartilhe suas idéias. Pesquisando em iniciar processos de fundo em Python não lançar qualquer luz ainda.

Eu recomendo usar o módulo de subprocesso em vez de os.system porque ele faz shell escapar para você e é, portanto, muito mais seguro: http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])
import os
cmd = 'ls -al'
os.system(cmd)

Se você quiser retornar os resultados do comando, você pode usar os.popen . No entanto, este é obsoleto desde a versão 2.6 em favor do subprocess módulo , que outras respostas ter coberto bem.

import os
os.system("your command")

Note que isso é perigoso, uma vez que o comando não é limpo. Deixo isso para você usar o Google para a documentação relevante sobre o 'os' e módulos 'sys'. Há um monte de funções (* exec e * desova) que vai fazer coisas semelhantes.

Existem muitas bibliotecas diferentes que lhe permitem chamar comandos externos com Python. Para cada biblioteca eu tenho dado uma descrição e mostrado um exemplo de chamar um comando externo. O comando que eu usei como exemplo é ls -l (lista todos os arquivos). Se você quiser saber mais sobre qualquer uma das bibliotecas que listei e ligados a documentação para cada um deles.

Fontes:

Estas são todas as bibliotecas:

Esperemos que isto irá ajudá-lo a tomar uma decisão sobre qual biblioteca para uso:)

subprocess

Subprocess permite chamar comandos externos e conectá-los à sua entrada / saída / tubos de erro (stdin, stdout e stderr). Subprocesso é a opção padrão para a execução de 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". Ele também pode ser usado para chamar comandos externos com os.system e os.popen (Nota: Há também uma subprocess.popen). OS será sempre executar o shell e é uma alternativa simples para pessoas que não precisam, ou não sabem como usar 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 subprocess que permite chamar os programas como se fossem funções. Isso é útil se você quiser 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

plumbum

plumbum é uma biblioteca para "como script de" programas em Python. Você pode chamar programas como funções que no sh. Plumbum é útil se você quiser executar um gasoduto sem a casca.

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

pexpect

pexpect permite que você gerar aplicações criança, controlá-los e encontrar padrões em sua produção. Esta é uma alternativa melhor para subprocess 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

tecido é uma biblioteca Python 2,5 e 2,7. Ele permite que você execute comandos local e remoto do escudo. Tecido é alternativa simples para a execução de 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 os seres humanos". Ele é usado como um invólucro de conveniência ao redor do módulo subprocess.

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

comandos

commands contém funções de invólucro para os.popen, mas que tenha sido removido a partir do Python 3 desde subprocess é uma alternativa melhor.

A edição foi baseada em comentário do J.F. Sebastian.

Eu sempre uso fabric para este coisas como:

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

Mas esta parece ser uma boa ferramenta:. sh (Python subprocesso interface)

Veja um exemplo:

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

Verifique a "pexpect" biblioteca Python também.

Ele permite controlar interativa de programas externos / comandos, mesmo ssh, ftp, telnet, etc Você pode simplesmente digitar algo como:

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

Se você precisa da saída do comando que você está chamando, então você pode 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'

Além disso, observe o desembolsar parâmetro .

Se shell é True, o comando especificado será executado através do shell. Isso pode ser útil se você estiver usando Python principalmente para o maior controle de fluxo que oferece sobre a maioria das conchas do sistema e ainda querem acesso conveniente a outra shell características tais como tubos de shell, wildcards nome de arquivo, expansão variável de ambiente e expansão do ~ para casa de um 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).

Biblioteca Padrão Com

A Use subprocess módulo (Python 3):

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

É a forma padrão recomendado. No entanto, as tarefas mais complicadas (tubos, saída, entrada, etc.) pode ser tedioso para construir e escrita.

Nota sobre a versão Python: Se você ainda está usando Python 2, subprocess.call funciona de forma similar.

Protip: shlex.split pode ajudar -lo a analisar o comando para run, call, e outras funções subprocess no caso de você não quer (ou não pode!) fornecê-los na forma de listas:

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

Com dependências externas

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

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

É o melhor invólucro subprocess. É multi-plataforma, ou seja, ele funciona em Windows e sistemas Unix-like. Instale por pip install plumbum.

Outra biblioteca popular é sh :

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

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

Isto é como eu correr meus comandos. Este código tem tudo que você precisa praticamente

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

Update:

subprocess.run é a abordagem recomendada a partir de Python 3.5 se seu código não precisa manter a compatibilidade com versões anteriores do Python. É mais consistente e oferece facilidade de uso como Enviado similar. (Piping não é como se simples. Consulte esta pergunta de como .)

Eis alguns exemplos de os docs .

Executar um processo:

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

Raise na corrida falhou:

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

saída de captura:

>>> 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 a tentar Envoy . É um wrapper para subprocesso, que por sua vez visa substituir os módulos mais antigos e funções . Envoy é subprocess para os seres humanos.

Exemplo de uso de o leia-me :

>>> 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
''

material da tubulação ao redor também:

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

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

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

Sem a saída do resultado:

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

Com a saída do resultado:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")

https://docs.python.org/2/library/subprocess.html

... ou para um comando muito simples:

import os
os.system('cat testfile')

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

os.system é OK, mas tipo de datado. Também não é muito seguro. Em vez disso, tente subprocess. subprocess não chama sh diretamente e é, portanto, mais seguro do que os.system.

Obtenha mais informações aqui .

Chamar um comando externo em Python

Simples, subprocess.run uso, que retorna um objeto CompletedProcess:

>>> 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 subprocessos invocando é usar a função run () para todos os casos de uso que ele pode manipular. Para casos de uso mais avançados, a interface Popen subjacente pode ser usado diretamente.

Aqui está um exemplo dos mais simples uso possível - e ele faz exatamente como pediu:

>>> 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 aguarda o comando para concluir com êxito, em seguida, retorna um objeto CompletedProcess. Ele pode, em alternativa levantar TimeoutExpired (se você lhe der um argumento timeout=) ou CalledProcessError (se ele falhar e você passar check=True).

Como você pode deduzir a partir do exemplo acima, stdout e stderr tanto get canalizada para o seu próprio stdout e stderr por padrão.

Podemos inspecionar o objeto retornado e veja o comando que foi dado e as returncode:

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

Captura de saída

Se você quiser capturar a saída, você pode passar subprocess.PIPE ao stderr ou stdout apropriado:

>>> 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 que é interessante e um pouco contra-intuitivo que a informação da versão é colocado para stderr em vez de stdout.)

Passe uma lista de comando

Pode-se facilmente passar de fornecer manualmente uma seqüência de comando (como sugere a pergunta) para fornecer uma corda construído programaticamente. Não construir cadeias de programação. Esta é uma questão de segurança potencial. É melhor assumir 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'

Note, única args deve 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 popenargs e kwargs são dadas para o construtor Popen. input pode ser uma seqüência de bytes (ou unicode, se especificar codificação ou universal_newlines=True) que será canalizada para stdin do subprocesso.

A documentação descreve timeout= e check=True melhor do que eu:

O argumento de tempo limite é passado para Popen.communicate (). Se o tempo limite expirar, o processo filho será morto e esperou. o exceção TimeoutExpired será re-raise após o processo de criança tem encerrado.

Se cheque é verdadeiro, e o processo é encerrado com um código de saída diferente de zero, um CalledProcessError exceção será levantada. Atributos de que exceção espera 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 aquele que eu poderia vir acima com:

>>> 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 expandido

Aqui está uma assinatura expandido, tal como consta da 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)

Note que isto indica que somente a lista de argumentos devem ser passados ??posicionalmente. Então, passar os argumentos restantes como argumentos.

Popen

Quando o uso Popen em vez disso? Eu iria lutar para encontrar caso de uso com base apenas os argumentos. o uso direto de Popen seria, no entanto, dar-lhe acesso a seus métodos, incluindo poll, 'send_signal', 'encerrar', e 'espera'.

Aqui está a assinatura Popen como dado na a fonte . Acho que este é o encapsulamento mais precisa das informações (como opposou para 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 o mais informativo é a documentação Popen :

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)

Executar um programa de criança em um novo processo. Em POSIX, os usos de classe os.execvp () - como o comportamento para executar o programa infantil. No Windows, a classe usa a função do Windows CreateProcess (). Os argumentos para Popen são os seguintes.

Compreender a documentação restante no Popen será deixado como um exercício para o leitor.

Use:

import os

cmd = 'ls -al'

os.system(cmd)

OS - Este módulo oferece uma forma portátil do usando a funcionalidade dependem do sistema operativo

.

Para mais funções os, aqui é a documentação.

Pode ser este simples:

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

Use o módulo os

import os
os.system("your command")

ex

import os
os.system("ifconfig")

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

I tendem a usar subprocess juntamente com shlex (para lidar escapar de cadeias 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)

os.system não permite que você para armazenar os resultados, por isso, se você deseja armazenar resultado em alguma lista ou algo funciona subprocess.call.

Eu gosto muito shell_command por sua simplicidade. Ele é construído em cima do módulo de subprocesso.

Aqui está um exemplo de docs:

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

Shameless plug, eu escrevi uma biblioteca para isso: P https://github.com/houqp/shell.py

É basicamente um wrapper para popen e shlex por agora. Ele também suporta tubulação comandos para que você possa comandos cadeia mais fácil em Python. Assim, você pode fazer coisas como:

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

No Linux, no caso de você gostaria de chamar um comando externo que será executado de forma independente (vai continuar correndo depois dos termina script Python), você pode usar uma fila simples como spooler tarefa ou o no comando

Um exemplo com spooler tarefa:

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

Notas sobre spooler tarefa (ts):

  1. Você pode definir o número de processos concorrentes para ser executado ( "slots") com:

    ts -S <number-of-slots>

  2. A instalação ts não exige privilégios de administrador. Você pode baixar e compilar o código fonte com um make simples, adicioná-lo ao seu caminho e está feito.

Você pode usar Popen, e então você pode verificar o status do processo:

from subprocess import Popen

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

Confira subprocess.Popen .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top