Executando comandos Bash em Python

299

Na minha máquina local, eu executo um script python que contém esta linha

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)

Isso funciona bem.

Em seguida, executo o mesmo código em um servidor e recebo a seguinte mensagem de erro

'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import  diag
ImportError: No module named swap

Então, o que fiz foi inserir um print bashCommandque me imprime além do comando no terminal antes de executá-lo os.system().

Obviamente, recebo novamente o erro (causado por os.system(bashCommand)), mas antes desse erro ele imprime o comando no terminal. Então eu apenas copiei essa saída e fiz uma cópia colar no terminal e apertei enter e funciona ...

Alguém tem idéia do que está acontecendo?

mkn
fonte
2
Parece haver uma diferença no ambiente, dependendo de como você executa cwm. Talvez você tenha alguma configuração .bashrcque configure o ambiente para o uso do bash interativo?
Sven Marnach
Você tentou executar o comando na linha de comando quando efetuou login no servidor? Sua postagem diz apenas que "a colou no terminal".
Sven Marnach
@Sven: sim, eu queria dizer que eu corri o comando diretamente no terminal do servidor
MKN
Parece haver uma diferença no PYTHONPATH, dependendo de como você executa cwm. Ou talvez exista uma diferença no PATH, e uma versão diferente do cwmseja chamada. Ou versões diferentes do Python. É realmente difícil de descobrir isso sem acesso à máquina ...
Sven Marnach

Respostas:

314

Não use os.system. Foi descontinuado em favor do subprocesso . A partir dos documentos : "Este módulo pretende substituir vários mais velhos módulos e funções: os.system, os.spawn".

Como no seu caso:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
user225312
fonte
8
Isso não fez o que eu queria quando precisei fazer um cd 'path\to\somewhere'seguido por outro comando bash que precisava ser executado em algum lugar. @ user225312
AWrightIV 4/13
36
@AWrightIV Se você precisa de seu subprocesso para ser executado em um diretório de trabalho particular, você pode usar o cwdargumento para Popen:subprocess.Popen(..., cwd='path\to\somewhere')
à prova d'água
7
Para meu comando, eu precisava do shell = True como aqui; stackoverflow.com/questions/18962785/...
user984003
4
É melhor shlex.split uso () em vez string.split () neste caso
Alexey Sviridov
4
... ( stdout=fileredireciona a saída para um arquivo neste caso. Implementa > file). Seria errado para passar ..., '>', 'file']no último comando esperando o redirecionamento (não vai funcionar sem um shell e se você usar um shell, você deve passar o comando como uma string)
jfs
186

Para expandir um pouco as respostas anteriores aqui, há vários detalhes que são geralmente ignorados.

  • Prefiro subprocess.run()mais subprocess.check_call()e amigos mais subprocess.call()sobre subprocess.Popen()mais os.system()sobreos.popen()
  • Entenda e provavelmente use text=True, aka universal_newlines=True.
  • Entenda o significado de shell=Trueou shell=Falsee como ele muda entre aspas e a disponibilidade de conveniências de shell.
  • Entenda as diferenças entre she Bash
  • Entenda como um subprocesso é separado de seu pai e geralmente não pode alterar o pai.
  • Evite executar o interpretador Python como um subprocesso do Python.

Esses tópicos são abordados com mais detalhes abaixo.

Preferir subprocess.run()ousubprocess.check_call()

o subprocess.Popen() função é uma força de trabalho de baixo nível, mas é difícil de usar corretamente e você acaba copiando / colando várias linhas de código ... que já existem convenientemente na biblioteca padrão como um conjunto de funções de wrapper de nível superior para várias finalidades, que são apresentados com mais detalhes a seguir.

Aqui está um parágrafo da documentação :

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

Infelizmente, a disponibilidade dessas funções do wrapper difere entre as versões do Python.

  • subprocess.run()foi introduzido oficialmente no Python 3.5. Ele pretende substituir todos os itens a seguir.
  • subprocess.check_output()foi introduzido no Python 2.7 / 3.1. É basicamente equivalente asubprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
  • subprocess.check_call()foi introduzido no Python 2.5. É basicamente equivalente asubprocess.run(..., check=True)
  • subprocess.call()foi introduzido no Python 2.4 no subprocessmódulo original ( PEP-324 ). É basicamente equivalente asubprocess.run(...).returncode

API de alto nível vs subprocess.Popen()

O refatorado e estendido subprocess.run()é mais lógico e mais versátil do que as funções herdadas mais antigas que ele substitui. Ele retorna um CompletedProcessobjeto que possui vários métodos que permitem recuperar o status de saída, a saída padrão e alguns outros resultados e indicadores de status do subprocesso concluído.

subprocess.run()é o caminho a percorrer se você simplesmente precisar de um programa para executar e retornar o controle ao Python. Para cenários mais envolvidos (processos em segundo plano, talvez com E / S interativa com o programa pai Python), você ainda precisa usar subprocess.Popen()e cuidar de todo o encanamento. Isso requer uma compreensão bastante complexa de todas as partes móveis e não deve ser realizada de ânimo leve. O Popenobjeto mais simples representa o processo (possivelmente ainda em execução) que precisa ser gerenciado a partir do seu código pelo restante da vida útil do subprocesso.

Talvez deva ser enfatizado que apenas subprocess.Popen()cria um processo. Se você deixar assim, você tem um subprocesso em execução simultaneamente com o Python, portanto, um processo "em segundo plano". Se ele não precisar fazer entrada ou saída ou coordenar-se com você, poderá fazer um trabalho útil em paralelo com o seu programa Python.

Evite os.system()eos.popen()

Desde o tempo eterno (bem, desde Python 2.5) a osdocumentação do módulo tem contido a recomendação de preferência subprocesssobre 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.

O problema system()é que, obviamente, depende do sistema e não oferece maneiras de interagir com o subprocesso. Ele simplesmente roda, com saída padrão e erro padrão fora do alcance do Python. A única informação que Python recebe de volta é o status de saída do comando (zero significa sucesso, embora o significado de valores diferentes de zero também dependa um pouco do sistema).

O PEP-324 (que já foi mencionado acima) contém uma justificativa mais detalhada sobre por que os.systemé problemático e como subprocesstenta resolver esses problemas.

os.popen()costumava ser ainda mais fortemente desencorajado :

Descontinuado desde a versão 2.6: Esta função está obsoleta. Use o subprocessmódulo

No entanto, desde algum momento no Python 3, ele foi reimplementado para simplesmente usar subprocesse redireciona para a subprocess.Popen()documentação para obter detalhes.

Entenda e use normalmente check=True

Você também notará que subprocess.call()possui muitas das mesmas limitações que os.system(). Em uso regular, você geralmente deve verificar se o processo foi concluído com êxito, qual subprocess.check_call()e o que subprocess.check_output()faz (onde o último também retorna a saída padrão do subprocesso concluído). Da mesma forma, você deve usar normalmente, check=Truea subprocess.run()menos que precise especificamente permitir que o subprocesso retorne um status de erro.

Na prática, com check=Trueou subprocess.check_*, Python lançará uma CalledProcessErrorexceção se o subprocesso retornar um status de saída diferente de zero.

Um erro comum subprocess.run()é omitir check=Truee surpreender-se quando o código downstream falhar se o subprocesso falhar.

Por outro lado, um problema comum check_call()e check_output()era que os usuários que usavam cegamente essas funções ficaram surpresos quando a exceção foi levantada, por exemplo, quando grepnão encontraram uma correspondência. (Você provavelmente deve substituir o grepcódigo Python nativo de qualquer maneira, conforme descrito abaixo.)

Tudo contado, você precisa entender como os comandos do shell retornam um código de saída e sob quais condições eles retornarão um código de saída diferente de zero (erro) e tomarão uma decisão consciente de como exatamente deve ser tratado.

Entenda e provavelmente use text=Trueakauniversal_newlines=True

Desde Python 3, cadeias internas ao Python são cadeias Unicode. Mas não há garantia de que um subprocesso gere saída Unicode ou seqüências de caracteres.

(Se as diferenças não forem imediatamente óbvias, recomenda-se a leitura pragmática do Node Batchelder Unicode , se não for totalmente obrigatória. Há uma apresentação em vídeo de 36 minutos por trás do link, se você preferir, embora a leitura da página provavelmente leve muito menos tempo. )

No fundo, o Python precisa buscar um bytesbuffer e interpretá-lo de alguma forma. Se ele contém um blob de dados binários, não deve ser decodificado em uma seqüência de caracteres Unicode, porque é um comportamento propenso a erros e indutor de erros - precisamente o tipo de comportamento irritante que envolveu muitos scripts Python 2, antes que houvesse uma maneira de distinguir adequadamente entre texto codificado e dados binários.

Com text=True, você diz ao Python que, na verdade, espera dados de texto de volta na codificação padrão do sistema e que eles devem ser decodificados em uma string Python (Unicode) da melhor maneira possível (geralmente UTF-8 em qualquer moderadamente) sistema de datas, exceto talvez o Windows?)

Se isso é não o que você pedir de volta, Python vai apenas dar-lhe bytescordas nos stdoute stderrcordas. Talvez em algum depois apontar-lhe que sei que eles eram cadeias de texto depois de tudo, e você sabe sua codificação. Então, você pode decodificá-los.

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

O Python 3.7 introduziu o alias mais curto, descritivo e compreensível textpara o argumento de palavra-chave, que antes era chamado de maneira enganosa universal_newlines.

Understand shell=Truevsshell=False

Com shell=Truevocê, você passa uma única string para o seu shell, e o shell o leva a partir daí.

Com shell=Falsevocê, passe uma lista de argumentos para o sistema operacional, ignorando o shell.

Quando você não possui um shell, salva um processo e se livra de uma quantidade bastante substancial de complexidade oculta, que pode ou não abrigar bugs ou mesmo problemas de segurança.

Por outro lado, quando você não possui um shell, não possui redirecionamento, expansão de curinga, controle de tarefas e um grande número de outros recursos do shell.

Um erro comum é usar shell=Truee ainda transmitir ao Python uma lista de tokens, ou vice-versa. Isso acontece em alguns casos, mas é realmente mal definido e pode ser interrompido de maneiras interessantes.

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

A réplica comum "mas funciona para mim" não é uma refutação útil, a menos que você entenda exatamente sob quais circunstâncias ela poderia parar de funcionar.

Exemplo de refatoração

Muitas vezes, os recursos do shell podem ser substituídos pelo código Python nativo. O Awk ou sedscripts simples provavelmente devem ser traduzidos simplesmente para Python.

Para ilustrar isso parcialmente, aqui está um exemplo típico, mas um pouco tolo, que envolve muitos recursos de shell.

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'round-trip min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

Algumas coisas a serem observadas aqui:

  • Com shell=Falsevocê, não é necessário citar que o shell requer em torno de strings. Colocar aspas de qualquer maneira provavelmente é um erro.
  • Geralmente, faz sentido executar o mínimo de código possível em um subprocesso. Isso lhe dá mais controle sobre a execução de dentro do seu código Python.
  • Dito isto, pipelines de shell complexos são tediosos e, às vezes, difíceis de reimplementar em Python.

O código refatorado também ilustra o quanto o shell realmente faz por você com uma sintaxe muito concisa - para melhor ou para pior. Python diz que explícito é melhor que implícito, mas o código Python é bastante detalhado e sem dúvida parece mais complexo do que isso realmente é. Por outro lado, oferece vários pontos onde você pode obter o controle no meio de outra coisa, como exemplifica trivialmente o aprimoramento de que podemos incluir facilmente o nome do host junto com a saída do comando shell. (Isso também não é difícil de fazer no shell, mas às custas de mais um desvio e talvez outro processo.)

Construções comuns do shell

Para completar, aqui estão breves explicações sobre alguns desses recursos do shell e algumas notas sobre como eles podem ser substituídos por recursos nativos do Python.

  • A expansão de curingas, também conhecida como globbing, pode ser substituída glob.glob()ou frequentemente por comparações simples de strings do Python, como for file in os.listdir('.'): if not file.endswith('.png'): continue. O Bash possui vários outros recursos de expansão, como .{png,jpg}expansão de chaves e {1..100}também a expansão de til ( ~expande para o diretório inicial e, geralmente, ~accountpara o diretório inicial de outro usuário)
  • Variáveis ​​de shell como $SHELLou $my_exported_varàs vezes podem simplesmente ser substituídas por variáveis ​​Python. Variáveis do shell exportados estão disponíveis como por exemplo os.environ['SHELL'](o significado exporté fazer com que a variável disponível para subprocessos -. Uma variável que não está disponível para subprocessos, obviamente, não estará disponível para Python executado como um subprocesso da casca, ou vice-versa A env=palavra-chave O argumento para subprocessmétodos permite definir o ambiente do subprocesso como um dicionário; portanto, é uma maneira de tornar uma variável Python visível para um subprocesso). Com shell=Falsevocê precisará entender como remover quaisquer aspas; por exemplo, cd "$HOME"é equivalente a os.chdir(os.environ['HOME'])sem aspas ao redor do nome do diretório. (Muitas vezescdde qualquer maneira, não é útil ou necessário, e muitos iniciantes omitem as aspas duplas em torno da variável e ficam impunes até um dia ... )
  • O redirecionamento permite que você leia um arquivo como entrada padrão e grave sua saída padrão em um arquivo. grep 'foo' <inputfile >outputfileabre outputfilepara escrever e inputfilepara ler e passa seu conteúdo como entrada padrão para grep, cuja saída padrão então chega outputfile. Isso geralmente não é difícil de substituir pelo código Python nativo.
  • Pipelines são uma forma de redirecionamento. echo foo | nlexecuta dois subprocessos, em que a saída padrão de echoé a entrada padrão de nl(no nível do SO, em sistemas semelhantes ao Unix, esse é um identificador de arquivo único). Se você não pode substituir uma ou as duas extremidades do pipeline pelo código Python nativo, talvez pense em usar um shell, afinal, especialmente se o pipeline tiver mais de dois ou três processos (embora veja o pipesmódulo na biblioteca padrão do Python ou vários de concorrentes de terceiros mais modernos e versáteis).
  • O controle de tarefas permite interromper as tarefas, executá-las em segundo plano, devolvê-las ao primeiro plano etc. Os sinais básicos do Unix para parar e continuar um processo também estão disponíveis no Python. Mas os trabalhos são uma abstração de nível superior no shell, que envolve grupos de processos, etc., que você precisa entender se quiser fazer algo assim no Python.
  • Citar no shell é potencialmente confuso até você entender que tudo é basicamente uma string. Portanto, ls -l /é equivalente a 'ls' '-l' '/', mas os citando torno literais é completamente opcional. Seqüências de caracteres não citadas que contêm metacaracteres de shell sofrem expansão de parâmetro, tokenização de espaço em branco e expansão de curinga; aspas duplas impedem a tokenização de espaço em branco e a expansão de curingas, mas permitem expansões de parâmetros (substituição de variável, substituição de comando e processamento de barra invertida). Isso é simples em teoria, mas pode ser desconcertante, especialmente quando há várias camadas de interpretação (um comando de shell remoto, por exemplo).

Entenda as diferenças entre she Bash

subprocessexecuta seus comandos shell, a /bin/shmenos que você solicite especificamente o contrário (exceto, é claro, no Windows, onde ele usa o valor da COMSPECvariável). Isso significa que vários recursos exclusivos do Bash, como matrizes, [[etc. não estão disponíveis.

Se você precisar usar a sintaxe apenas do Bash, poderá passar o caminho para o shell como executable='/bin/bash'(onde, é claro, se o seu Bash estiver instalado em outro lugar, será necessário ajustar o caminho).

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

A subprocessé separado de seu pai e não pode alterá-lo

Um erro um tanto comum é fazer algo como

subprocess.run('foo=bar', shell=True)
subprocess.run('echo "$foo"', shell=True)  # Doesn't work

que, além da falta de elegância, também trai uma falta fundamental de compreensão da parte "sub" do nome "subprocesso".

Um processo filho é executado completamente separado do Python e, quando termina, o Python não tem idéia do que fez (além dos indicadores vagos que podem inferir do status de saída e saída do processo filho). Uma criança geralmente não pode mudar o ambiente dos pais; não pode definir uma variável, alterar o diretório de trabalho ou, em muitas palavras, se comunicar com seu pai sem a cooperação do pai.

A correção imediata nesse caso específico é executar os dois comandos em um único subprocesso;

subprocess.run('foo=bar; echo "$foo"', shell=True)

embora obviamente esse caso de uso específico não exija o shell. Lembre-se, você pode manipular o ambiente do processo atual (e, portanto, também seus filhos) via

os.environ['foo'] = 'bar'

ou passar uma configuração de ambiente para um processo filho com

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(para não mencionar a refatoração óbvia subprocess.run(['echo', 'bar']); mas echoé um mau exemplo de algo para executar em um subprocesso, é claro).

Não execute o Python a partir do Python

Este é um conselho um pouco dúbio; Certamente, há situações em que faz sentido ou é mesmo um requisito absoluto executar o interpretador Python como um subprocesso de um script Python. Mas com muita frequência, a abordagem correta é simplesmente para importo outro módulo Python no seu script de chamada e chamar suas funções diretamente.

Se o outro script Python estiver sob seu controle e não for um módulo, considere transformá-lo em um . (Essa resposta já é muito longa, portanto não vou me aprofundar nos detalhes aqui.)

Se você precisar de paralelismo, poderá executar funções Python em subprocessos com o multiprocessingmódulo. Também existe a threadingexecução de várias tarefas em um único processo (que é mais leve e oferece mais controle, mas também mais restrito, pois os segmentos de um processo são fortemente acoplados e vinculados a um único GIL .)

triplo
fonte
2
Para uma exposição mais detalhada de como você pode evitar chamar Python como um subprocesso, consulte esta resposta em uma pergunta tangencialmente semelhante.
Tripleee
4
me surpreende que eu tenha que postar uma nova resposta para uma pergunta tão básica, a fim de mostrar como executar o comando da pergunta linguisticamente. Sua resposta é longa, mas não vejo esse exemplo. Não relacionado: evite cultos de carga. Se check_call () funcionar no seu caso, use-o. Eu tive que corrigir um código que era usado run()às cegas. A falta check=Truecausou um erro que seria evitado se check_call fosse usado - "check" está no nome, você não pode perdê-lo - é o padrão correto: não ignore os erros silenciosamente. Eu não li mais.
JFS
1
@jfs Obrigado pelo feedback, eu estava planejando adicionar uma seção sobre o Bash vs, shmas você me venceu. Estou tentando explicar detalhadamente os detalhes para ajudar os iniciantes, para os quais essas armadilhas não são óbvias, e isso fica um pouco demorado. O seu deve ser suficiente o suficiente; +1
triplicar
Tem stderr/stdout = subprocess.PIPEuma sobrecarga de desempenho superior às configurações padrão?
Stringers
1
@ Stringers Eu não testei, mas não vejo por que deveria. Se você conectar esses tubos a algo que faz algum processamento, é claro que esse processamento precisa ser considerado; mas isso não acontece no próprio tubo. O padrão é não capturar stdout ou stderr, ou seja, o que for impresso lá fora da visibilidade e controle do Python, assim como acontece com os.system().
Tripleee
41

Chame-o com subprocesso

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

O erro que você está recebendo parece ser porque não há módulo de troca no servidor, você deve instalar a troca no servidor e executar o script novamente

Jakob Bowyer
fonte
3
O swapmódulo está obviamente lá, porque a execução do comando a partir do shell funciona.
Sven Marnach
2
Não no servidor, quando ele é executado no servidor, ocorre um erro de importação.
Jakob Bowyer
@ mkn: "Então eu apenas copiei essa saída e fiz uma cópia colar no terminal e apertei enter e funciona ..." - Você tentou isso no servidor ou na sua máquina?
Sven Marnach
Você está executando isso em um computador independente, mas não está funcionando quando você o executa no servidor? Ou você é capaz de executá-lo em um terminal servidor, mas não o próprio servidor
Jakob Bowyer
1
está errado Se você não usar shell=True, deve usar uma lista para passar vários argumentos, ou seja, use em ['a', 'b', 'c']vez de 'a b c'. Embora uma divisão ingênua não funcione devido a > file(redirecionamento de shell) no comando. Mais detalhes
jfs 31/10
18

É possível usar o programa bash, com o parâmetro -c para executar os comandos:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])
Navalha
fonte
2
subprocess.check_output(bashCommand, shell=True)faz a mesma coisa. Se o seu comando for uma sequência estática, tente analisá-lo em uma lista e evite o shell=True; embora neste caso você precisa do shell para o redirecionamento de qualquer maneira, ou então você terá que refatorar-lo para pura Python -with open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
tripleee
@ Nota do triplo: /bin/sh(usado pelo subprocesso) não é necessariamente bash(você não pode usar basismos). Embora se possa usar, executable='/bin/bashse desejar. Aqui está um exemplo de código
jfs
2
é a primeira resposta em que o comando deve iniciar com êxito (as respostas aceitas e a segunda popular estão erradas. Um pequeno problema: check_output()é inútil aqui (a saída está sempre vazia devido ao > fileredirecionamento; use em check_call()vez disso.
jfs
16

Você pode usar subprocess, mas sempre achei que não era uma maneira 'pitônica' de fazê-lo. Então, criei o Sultan (plugue descarado) que facilita a execução das funções da linha de comando.

https://github.com/aeroxis/sultan

David Daniel
fonte
3
Bem feito! Muito mais limpo e mais intuitivo que o subprocesso.
Mjd2
Muito obrigado! Eu estou feliz em ouvir isso!
David Daniel
2
Isso deve ser honestamente adotado na biblioteca padrão.
Joshua Detwiler
1
Existe uma maneira de capturar a saída do terminal usando o Sultan?
alvas 29/08/18
Sim, você pode @ alvas ... Aqui estão os documentos sobre como fazê-lo: sultan.readthedocs.io/en/latest/…
David Daniel
7

De acordo com o erro, você está perdendo um pacote chamado swap no servidor. Isso /usr/bin/cwmrequer isso. Se você estiver no Ubuntu / Debian, instale python-swapusando o aptitude.

kichik
fonte
mas funciona quando eu corro diretamente no terminal ... então a troca deve estar lá, não?
MKN
existem duas opções. ou ele não consegue encontrar swapou não deveria ter importado em primeiro lugar. você pode import swapmanualmente? funciona?
Kichik
hm eu não posso. Se eu iniciar o python digitando python no terminal e digitar import swap, recebi o erro "ImportError: No module named swap". O estranho ainda é que ele funciona quando eu executar o comando cwm diretamente no terminal do servidor
MKN
Tente imprimir sys.pathonde está funcionando e onde não está. Em seguida, tente procurar a pasta swap ou swap.py nas pastas impressas. Como disse Sven, pode haver um problema com esses caminhos, e isso ajudará você a descobrir.
Kichik
4

Também você pode usar 'os.popen'. Exemplo:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

Resultado:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None
ricardo130
fonte
1
A documentação contém uma grande caixa vermelha: " Descontinuado desde a versão 2.6: Esta função está obsoleta. Use o subprocessmódulo."
Tripleee
1
Para ser justo, os.popennão tem mais esse aviso e é simplesmente um invólucro fino subprocess.Popen()agora.
Tripleee 6/05/19
4

Para executar o comando sem um shell, passe o comando como uma lista e implemente o redirecionamento no Python usando [subprocess]:

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

Nota: não > test.ntno final. stdout=fileimplementa o redirecionamento.


Para executar o comando usando o shell no Python, passe o comando como uma string e ative shell=True:

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

Aqui está o shell é responsável pelo redirecionamento de saída ( > test.ntestá no comando).


Para executar um comando bash que usa bashisms, especifique explicitamente o executável do bash, por exemplo, para emular a substituição do processo do bash :

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')
jfs
fonte
Talvez mencione que isso .split()não é adequado quando há seqüências de caracteres entre aspas etc. Há uma rotina separada shlex.split()que lida com sintaxe de shell arbitrariamente complexa.
tripleee
@tripleee os .split()trabalhos neste caso. shlex.split()às vezes pode ser útil, mas também pode falhar em alguns casos. Há muitas coisas que poderiam ser mencionadas. Você pode começar com o link para a descrição da tag do subprocesso fornecida acima.
JFS
0

A maneira pitônica de fazer isso é usar subprocess.Popen

subprocess.Popen faz uma lista em que o primeiro elemento é o comando a ser executado, seguido por qualquer argumento de linha de comando.

Como um exemplo:

import subprocess

args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line

args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line
RewordedAnswers
fonte
Não, o último exemplo é o mesmo que executar echo -v '"Hello Again!"'aspas simples entre aspas duplas.
Tripleee
Além disso, para usar corretamente subprocesss.Popen, você precisa gerenciar o objeto de processo resultante (no mínimo, execute a wait()para impedir que ele se transforme em um processo zumbi).
Tripleee 6/05/19