As outras respostas aqui explicam adequadamente as advertências de segurança que também são mencionadas na subprocessdocumentaçã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 Popense um dos invólucros mais simples do subprocesspacote fizer o que você deseja. Se você tem um Python recente o suficiente, provavelmente deve usar subprocess.run.
- Com
check=Trueele falhará se o comando que você executou falhar.
- Com
stdout=subprocess.PIPEele irá capturar a saída do comando.
- De maneira um tanto obscura,
universal_newlines=Trueele decodificará a saída em uma string Unicode adequada (apenas bytesna codificação do sistema, no Python 3).
Caso contrário, para muitas tarefas, você deseja check_outputobter a saída de um comando, enquanto verifica se foi bem-sucedido ou check_callse 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 delsprograma no Unix seshell=True. O argumento string deve ser usadoshell=Truena maioria dos casos, em vez de uma lista.