As outras respostas aqui explicam adequadamente as advertências de segurança que também são mencionadas na subprocess
documentação. Além disso, a sobrecarga de iniciar um shell para iniciar o programa que você deseja executar geralmente é desnecessária e definitivamente boba para situações em que você realmente não usa nenhuma das funcionalidades do shell. Além disso, a complexidade oculta adicional deve assustá-lo, especialmente se você não estiver muito familiarizado com o shell ou os serviços que ele fornece.
Onde as interações com o shell não são triviais, você agora exige que o leitor e o mantenedor do script Python (que pode ou não ser seu futuro) entendam tanto o Python quanto o shell. Lembre-se do lema do Python "explícito é melhor que implícito"; mesmo quando o código Python for um pouco mais complexo que o script de shell equivalente (e geralmente muito conciso), é melhor remover o shell e substituir a funcionalidade pelas construções nativas do Python. Minimizar o trabalho realizado em um processo externo e manter o controle dentro do seu próprio código, na medida do possível, geralmente é uma boa idéia, simplesmente porque melhora a visibilidade e reduz os riscos de efeitos colaterais desejados ou indesejados.
Expansão curinga, interpolação variável e redirecionamento são todos fáceis de substituir por construções nativas do Python. Um complexo pipeline de shell em que partes ou todas não possam ser razoavelmente reescritas no Python seria a única situação em que talvez você possa considerar o uso do shell. Você ainda deve entender as implicações de desempenho e segurança.
No caso trivial, para evitar shell=True
, basta substituir
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
com
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
Observe como o primeiro argumento é uma lista de cadeias de caracteres a serem passadas execvp()
e como citar cadeias de caracteres e metacaracteres de shell com barra invertida geralmente não são necessários (ou úteis ou corretos). Talvez veja também Quando agrupar aspas em torno de uma variável de shell?
Como um aparte, muitas vezes você deseja evitar Popen
se um dos invólucros mais simples do subprocess
pacote fizer o que você deseja. Se você tem um Python recente o suficiente, provavelmente deve usar subprocess.run
.
- Com
check=True
ele falhará se o comando que você executou falhar.
- Com
stdout=subprocess.PIPE
ele irá capturar a saída do comando.
- De maneira um tanto obscura,
universal_newlines=True
ele decodificará a saída em uma string Unicode adequada (apenas bytes
na codificação do sistema, no Python 3).
Caso contrário, para muitas tarefas, você deseja check_output
obter a saída de um comando, enquanto verifica se foi bem-sucedido ou check_call
se não há saída a ser coletada.
Termino com uma citação de David Korn: "É mais fácil escrever um shell portátil do que um script de shell portátil". Even subprocess.run('echo "$HOME"', shell=True)
não é portátil para Windows.
-l
é passado para/bin/sh
(o shell) em vez dels
programa no Unix seshell=True
. O argumento string deve ser usadoshell=True
na maioria dos casos, em vez de uma lista.