manipulando - melhores bibliotecas python




Por que usar os métodos do módulo os do Python ao invés de executar comandos do shell diretamente? (4)

Eu estou tentando entender qual é a motivação por trás usando funções de biblioteca do Python para executar tarefas específicas do sistema operacional, como criar arquivos / diretórios, alterar atributos de arquivo, etc. em vez de apenas executar esses comandos via os.system() ou subprocess.call()

Por exemplo, por que eu iria querer usar os.chmod vez de fazer os.system("chmod...") ?

Eu entendo que é mais "pythonic" usar os métodos de biblioteca disponíveis do Python tanto quanto possível, em vez de simplesmente executar comandos shell diretamente. Mas, existe alguma outra motivação por trás disso, do ponto de vista da funcionalidade?

Estou falando apenas de executar comandos simples de shell de uma linha aqui. Quando precisamos de mais controle sobre a execução da tarefa, eu entendo que usar o módulo de subprocess faz mais sentido, por exemplo.


  1. É mais rápido , os.system e subprocess.call criam novos processos que são desnecessários para algo tão simples. Na verdade, os.system e subprocess.call com o argumento shell geralmente criam pelo menos dois novos processos: o primeiro é o shell, e o segundo é o comando que você está executando (se não for um shell embutido como test ).

  2. Alguns comandos são inúteis em um processo separado . Por exemplo, se você executar os.spawn("cd dir/") , ele alterará o diretório de trabalho atual do processo filho, mas não do processo Python. Você precisa usar os.chdir para isso.

  3. Você não precisa se preocupar com caracteres especiais interpretados pelo shell. os.chmod(path, mode) funcionará não importa o nome do arquivo, ao passo que os.spawn("chmod 777 " + path) falhará horrivelmente se o nome do arquivo for algo semelhante ; rm -rf ~ ; rm -rf ~ . (Observe que você pode contornar isso se você usar subprocess.call sem o argumento de shell .)

  4. Você não precisa se preocupar com nomes de arquivos que começam com um traço . os.chmod("--quiet", mode) irá alterar as permissões do arquivo chamado --quiet , mas os.spawn("chmod 777 --quiet") falhará, pois --quiet é interpretado como um argumento. Isso é verdade mesmo para subprocess.call(["chmod", "777", "--quiet"]) .

  5. Você tem menos preocupações entre plataformas e cross-shell, como a biblioteca padrão do Python deve lidar com isso para você. O seu sistema tem o comando chmod ? Está instalado? Ele suporta os parâmetros que você espera que ele suporte? O módulo os tentará ser tão multi-plataforma quanto possível e documenta quando isso não for possível.

  6. Se o comando que você está rodando tem uma saída que lhe interessa, você precisa analisá-lo, o que é mais complicado do que parece, já que você pode esquecer os casos de canto (nomes de arquivos com espaços, tabulações e novas linhas), mesmo quando você Não me importo com a portabilidade.


É mais seguro. Para se ter uma ideia, aqui está um script de exemplo

import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)

Se a entrada do usuário foi test; rm -rf ~ test; rm -rf ~ isso test; rm -rf ~ o diretório inicial.

É por isso que é mais seguro usar a função incorporada.

Daí porque você deve usar subprocessado em vez de sistema também.


As chamadas de shell são específicas do sistema operacional, enquanto as funções do módulo do Python não são, na maioria das vezes. E evite gerar um subprocesso.


Existem quatro casos fortes para preferir os métodos mais específicos do Python no módulo os sobre o uso do os.system ou do módulo de subprocess ao executar um comando:

  • Redundância - gerar outro processo é redundante e desperdiça tempo e recursos.
  • Portabilidade - Muitos dos métodos no módulo os estão disponíveis em múltiplas plataformas, enquanto muitos comandos shell são específicos do sistema operacional.
  • Entendendo os resultados - Gerar um processo para executar comandos arbitrários obriga você a analisar os resultados da saída e entender se e por que um comando fez algo errado.
  • Segurança - Um processo pode potencialmente executar qualquer comando que seja dado. Este é um design fraco e pode ser evitado usando métodos específicos no módulo os .

Redundância (veja código redundante ):

Você está realmente executando um "intermediário" redundante no seu caminho para as eventuais chamadas do sistema ( chmod em seu exemplo). Este intermediário é um novo processo ou sub-shell.

De os.system :

Execute o comando (uma string) em um subshell ...

E o subprocess é apenas um módulo para gerar novos processos.

Você pode fazer o que precisa sem gerar esses processos.

Portabilidade (veja portabilidade do código fonte ):

O objetivo do módulo os é fornecer serviços genéricos do sistema operacional e sua descrição começa com:

Este módulo fornece uma maneira portátil de usar a funcionalidade dependente do sistema operacional.

Você pode usar os.listdir em ambas as janelas e unix. Tentar usar os.system / subprocess para essa funcionalidade forçará você a manter duas chamadas (para ls / dir ) e verificar em qual sistema operacional você está. Isso não é tão portátil e causará ainda mais frustração no futuro (consulte Como gerenciar saída ).

Entendendo os resultados do comando:

Suponha que você queira listar os arquivos em um diretório.

Se você estiver usando os.system("ls") / subprocess.call(['ls']) , você só pode recuperar a saída do processo, que é basicamente uma grande cadeia com os nomes dos arquivos.

Como você pode dizer a um arquivo com um espaço em seu nome de dois arquivos?

E se você não tiver permissão para listar os arquivos?

Como você deve mapear os dados para objetos python?

Estes são apenas o topo da minha cabeça, e embora existam soluções para estes problemas - por que resolver novamente um problema que foi resolvido para você?

Este é um exemplo de seguir o princípio Don't Repeat Yourself (Frequentemente referenciado como "DRY") por não repetir uma implementação que já existe e está disponível gratuitamente para você.

Segurança:

os.system e subprocess são poderosos. É bom quando você precisa desse poder, mas é perigoso quando você não precisa. Quando você usa os.listdir , você sabe que não pode fazer nada além de listar arquivos ou gerar um erro. Quando você usa os.system ou subprocess para obter o mesmo comportamento, pode acabar fazendo algo que não pretendia fazer.

Segurança de Injeção (veja exemplos de injeção de casca ) :

Se você usar a entrada do usuário como um novo comando, basicamente terá dado a ele um shell. Isso é muito parecido com a injeção SQL fornecendo um shell no banco de dados para o usuário.

Um exemplo seria um comando do formulário:

# ... read some user input
os.system(user_input + " some continutation")

Isso pode ser facilmente explorado para executar qualquer código arbitrário usando a entrada: NASTY COMMAND;# para criar o eventual:

os.system("NASTY COMMAND; # some continuation")

Existem muitos comandos que podem colocar o seu sistema em risco.





operating-system