pelo programas abrir como Chamando um comando externo em Python



15 Answers

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 executar vários comandos de uma só vez dessa maneira e configurar canais e redirecionamento de entrada / saída. Por exemplo:

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

    No entanto, embora isso seja conveniente, você precisa manipular manualmente o escape de caracteres de shell, como espaços, etc. Por outro lado, isso também permite executar comandos que são simplesmente comandos de shell e não programas realmente externos. Veja a documentação .

  2. stream = os.popen("some_command with args") fará a mesma coisa que os.system exceto que lhe dá um objeto semelhante a um arquivo que você pode usar para acessar entrada / saída padrão para aquele processo. Existem 3 outras variantes do popen que lidam com o i / o de forma ligeiramente diferente. Se você passar tudo como uma string, então seu comando é passado para o shell; Se você passá-los como uma lista, então você não precisa se preocupar em escapar de nada. Veja a documentação .

  3. A classe Popen do módulo subprocess . Isto é pretendido como um substituto para os.popen mas tem o lado negativo de ser um pouco mais complicado em virtude de 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 lá em uma classe unificada em vez de 4 diferentes funções popen. Veja a documentação .

  4. A função de call do módulo de subprocess . Isto é basicamente como a classe Popen e pega todos os mesmos argumentos, mas simplesmente espera até que o comando seja completado e lhe dê o código de retorno. Por exemplo:

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

    Veja a documentação .

  5. Se você estiver no Python 3.5 ou posterior, você pode usar a nova função subprocess.run , que é muito parecida com a anterior, mas ainda mais flexível e retorna um objeto CompletedProcess quando o comando termina de ser executado.

  6. O módulo os também tem todas as funções fork / exec / spawn que você tem em um programa em C, mas eu não recomendo usá-las diretamente.

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

Finalmente, por favor, esteja ciente que para todos os métodos onde você passa o comando final para ser executado pelo shell como uma string e você é responsável por escapar dele. 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 alguma parte da string. Se não tiver certeza, use apenas esses métodos 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 entre "minha mãe não me amou && rm -rf /".

python chamar outro python

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




Algumas dicas sobre como separar o processo filho do chamador (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 do que o processo de execução do script CGI.

O exemplo clássico dos documentos do 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 'call subprocess' até que o longtask.py termine. Mas não está claro o que acontece depois da linha 'mais algum código aqui' do exemplo.

Minha plataforma de destino era freebsd, mas o desenvolvimento estava no Windows, então enfrentei o problema no Windows primeiro.

No windows (win xp), o processo pai não terminará até que o longtask.py termine seu trabalho. Não é o que você quer no script CGI. O problema não é específico do Python, na comunidade PHP os problemas são os mesmos.

A solução é passar o DETACHED_PROCESS Process Creation Flag para a função CreateProcess subjacente na API do win. Se acontecer de você ter instalado o pywin32, você 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 é concluído, ele também finaliza os processos filhos. E isso não é o que você quer no script CGI. Algumas experiências mostraram que o problema parecia estar em compartilhar 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)

Eu não verifiquei 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 ideias. Pesquisando sobre o início de processos em segundo plano no Python não lança nenhuma luz ainda.







Eu sempre uso fabric para 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 (interface do subprocesso Python) .

Veja um exemplo:

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



Existem várias bibliotecas diferentes que permitem chamar comandos externos com o Python. Para cada biblioteca eu dei uma descrição e mostrei um exemplo de chamar um comando externo. O comando que usei como exemplo é ls -l (lista todos os arquivos). Se você quiser saber mais sobre qualquer uma das bibliotecas que listei e vinculou a documentação para 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

Subprocesso permite que você chame comandos externos e conecte-os a seus canais de entrada / saída / erro (stdin, stdout e stderr). O 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: Há também um subprocesso.popen). O OS sempre executará o shell e é uma alternativa simples para pessoas que não precisam ou não sabem como usar o 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ê 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 programas Python "script-like". Você pode chamar programas como funções como sh . Plumbum é útil se você deseja executar um pipeline sem o shell.

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

pexpe

O pexpect permite gerar aplicativos filhos, controlá-los e encontrar padrões em suas saídas. Essa é uma alternativa melhor para o subprocesso de 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 2.5 e 2.7 do Python. Ele permite que você execute comandos shell locais e remotos. 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". Ele é usado como um wrapper de conveniência em torno do módulo de subprocess .

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, pois o subprocess é uma alternativa melhor.

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




É assim que eu corro meus comandos. Este código tem tudo 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()



Atualizar:

subprocess.run é a abordagem recomendada a partir do Python 3.5 se seu código não precisar manter a compatibilidade com versões anteriores do Python. É mais consistente e oferece uma facilidade de uso semelhante à do Envoy. (Tubulação não é tão simples. Veja esta pergunta para saber como ).

Aqui estão alguns exemplos dos documentos .

Execute um processo:

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

Levantar na execução falhada:

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

Capturar 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 https://github.com/kennethreitz/envoy . É um invólucro para o subprocesso, que, por sua vez, visa substituir os módulos e funções mais antigos. Envoy é 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
''

Material de tubulação ao redor também:

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

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

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






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



Pode ser simples assim:

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



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




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




Plugue sem vergonha, eu 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 tubulação para que você possa encadear comandos com mais facilidade no Python. Então você pode fazer coisas como:

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



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

Aqui está um exemplo dos documentos:

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



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:

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

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



Related