Estou chamando processos diferentes com o subprocess
módulo. No entanto, eu tenho uma pergunta.
Nos seguintes códigos:
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
e
callProcess = subprocess.Popen(['ls', '-l']) # without shell
Ambos funcionam. Depois de ler os documentos, soube que isso shell=True
significa executar o código através do shell. Então, na ausência, o processo é iniciado diretamente.
Então, o que devo preferir para o meu caso - preciso executar um processo e obter sua saída. Que benefício eu tenho ao chamá-lo de dentro ou fora do shell?
python
subprocess
user225312
fonte
fonte
-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.shell=True
aFalse
e vice-versa é um erro. From docs : "No POSIX com shell = True, (...) Se args for uma sequência, o primeiro item especificará a sequência de comandos e quaisquer itens adicionais serão tratados como argumentos adicionais para o próprio shell.". No Windows, há conversão automática , o que pode ser indesejável.Respostas:
O benefício de não ligar através do shell é que você não está invocando um 'programa misterioso'. No POSIX, a variável de ambiente
SHELL
controla qual binário é chamado como o "shell". No Windows, não há descendente do shell bourne, apenas o cmd.exe.Portanto, invocar o shell chama um programa de escolha do usuário e depende da plataforma. De um modo geral, evite invocações através do shell.
A chamada por meio do shell permite expandir variáveis de ambiente e arquivar globs de acordo com o mecanismo usual do shell. Nos sistemas POSIX, o shell expande os globs de arquivo para uma lista de arquivos. No Windows, um arquivo glob (por exemplo, "*. *") Não é expandido pelo shell, de qualquer maneira (mas as variáveis de ambiente em uma linha de comando são expandidas pelo cmd.exe).
Se você acha que deseja expansões de variáveis de ambiente e globs de arquivos, pesquise os
ILS
ataques do 1992-ish em serviços de rede que executavam invocações de subprogramas por meio do shell. Exemplos incluem as váriassendmail
backdoors envolvendoILS
.Em resumo, use
shell=False
.fonte
$SHELL
não está correta. Para citar subprocess.html: "No Unix comshell=True
, o shell é padronizado como/bin/sh
". (não$SHELL
)open
se desejar maneiras seguras de chamar um programa e capturar a saída.fonte: Módulo Subprocesso
fonte
Um exemplo em que as coisas podem dar errado com Shell = True é mostrado aqui
Verifique o documento aqui: subprocess.call ()
fonte
A execução de programas através do shell significa que toda a entrada do usuário passada para o programa é interpretada de acordo com as regras de sintaxe e semântica do shell chamado. Na melhor das hipóteses, isso só causa transtornos ao usuário, porque ele deve obedecer a essas regras. Por exemplo, caminhos que contenham caracteres especiais de shell, como aspas ou espaços em branco, devem ser escapados. Na pior das hipóteses, causa vazamentos de segurança, porque o usuário pode executar programas arbitrários.
shell=True
Às vezes, é conveniente usar recursos específicos do shell, como divisão de palavras ou expansão de parâmetros. No entanto, se esse recurso for necessário, utilize outros módulos (por exemplo,os.path.expandvars()
para expansão de parâmetros oushlex
divisão de palavras). Isso significa mais trabalho, mas evita outros problemas.Em resumo: Evite
shell=True
por todos os meios.fonte
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 substituircom
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 dosubprocess
pacote fizer o que você deseja. Se você tem um Python recente o suficiente, provavelmente deve usarsubprocess.run
.check=True
ele falhará se o comando que você executou falhar.stdout=subprocess.PIPE
ele irá capturar a saída do comando.universal_newlines=True
ele decodificará a saída em uma string Unicode adequada (apenasbytes
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 oucheck_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.fonte
shell=True
, muitas com excelentes respostas. Por acaso, você escolheu o que é o motivo .subprocess