Ao usar os.system (), muitas vezes é necessário escapar nomes de arquivos e outros argumentos passados como parâmetros para comandos. Como posso fazer isso? De preferência algo que funcionaria em vários sistemas operacionais / shells, mas em particular no bash.
Atualmente, estou fazendo o seguinte, mas tenho certeza de que deve haver uma função de biblioteca para isso, ou pelo menos uma opção mais elegante / robusta / eficiente:
def sh_escape(s):
return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")
os.system("cat %s | grep something | sort > %s"
% (sh_escape(in_filename),
sh_escape(out_filename)))
Edit: Aceitei a resposta simples de usar aspas, não sei por que não pensei nisso; Eu acho que porque eu vim do Windows, onde 'e "se comportam de maneira um pouco diferente.
Em relação à segurança, entendo a preocupação, mas, neste caso, estou interessado em uma solução rápida e fácil fornecida pelo os.system (), e a origem das strings não é gerada pelo usuário ou, pelo menos, inserida por um usuário confiável (eu).
sh_escape
função ideal escaparia dos;
espaços e e removeria o problema de segurança simplesmente criando um arquivo chamado algo parecidofoo.txt\;\ rm\ -rf\ /
.Respostas:
Isto é o que eu uso:
O shell sempre aceita um nome de arquivo citado e remove as aspas circundantes antes de passá-lo para o programa em questão. Notavelmente, isso evita problemas com nomes de arquivos que contêm espaços ou qualquer outro tipo de metacaractere desagradável do shell.
Atualização : se você estiver usando o Python 3.3 ou posterior, use shlex.quote em vez de usar o seu próprio.
fonte
shlex
oupipes
. Esses módulos python erroneamente supor que os caracteres especiais são a única coisa que precisa ser citado, o que significa que a Shell palavras-chave (comotime
,case
ouwhile
) será analisado quando esse comportamento não é esperado. Por esse motivo, eu recomendaria usar a rotina de aspas simples nesta resposta, porque ela não tenta ser "inteligente" e, portanto, não tem esses casos tolos.shlex.quote()
faz o que você quer desde o python 3.(Use
pipes.quote
para suportar python 2 e python 3)fonte
commands.mkarg
. Também adiciona um espaço inicial (fora das aspas) que pode ou não ser desejável. É interessante como suas implementações são bem diferentes umas das outras e também muito mais complicado do que a resposta de Greg Hewgill.pipes.quote
não é mencionado na documentação padrão da biblioteca para o módulo pipescommand.mkarg
foi descontinuado e removido no 3.x, enquanto o pipes.quote permaneceu.shlex.quote()
no 3.3,pipes.quote()
mantido por compatibilidade. [ bugs.python.org/issue9723]Talvez você tenha uma razão específica para usar
os.system()
. Mas se não, você provavelmente deveria estar usando osubprocess
módulo . Você pode especificar os tubos diretamente e evitar o uso da concha.O seguinte é do PEP324 :
fonte
subprocess
(especialmente comcheck_call
etc) geralmente é dramaticamente superior, mas há alguns casos em que o escape de shell ainda é útil. O principal que eu encontro é quando tenho que chamar comandos remotos ssh.Talvez
subprocess.list2cmdline
seja uma chance melhor?fonte
subprocess.list2cmdline(["'",'',"\\",'"'])
dá' "" \ \"
list2cmdline
está de acordo com a sintaxe do cmd.exe do Windows ( consulte a função docstring no código fonte do Python ).shlex.quote
está de acordo com a sintaxe do Unix bourne shell, no entanto, geralmente não é necessário, pois o Unix tem um bom suporte para transmitir argumentos diretamente. O Windows exige praticamente que você passe uma única sequência com todos os seus argumentos (portanto, a necessidade de escape apropriado).Observe que o pipes.quote é realmente quebrado no Python 2.5 e Python 3.1 e não é seguro de usar - ele não manipula argumentos de comprimento zero.
Veja Python edição 7476 ; foi corrigido no Python 2.6 e 3.2 e mais recente.
fonte
Aviso : Esta é uma resposta para o Python 2.7.x.
Segundo a fonte ,
pipes.quote()
é uma maneira de " Citar com segurança uma string como um único argumento para / bin / sh ". (Embora tenha sido descontinuado desde a versão 2.7 e finalmente exposto publicamente no Python 3.3 como ashlex.quote()
função.)Por outro lado ,
subprocess.list2cmdline()
é uma maneira de " Traduzir uma sequência de argumentos em uma sequência de linhas de comando, usando as mesmas regras do tempo de execução do MS C ".Aqui estamos, a maneira independente da plataforma de citar seqüências de caracteres para linhas de comando.
Uso:
fonte
Acredito que o os.system invoque qualquer shell de comando configurado para o usuário, então não acho que você possa fazê-lo de maneira independente da plataforma. Meu shell de comando pode ser qualquer coisa, desde bash, emacs, ruby ou até quake3. Alguns desses programas não esperam o tipo de argumento que você está passando para eles e, mesmo que o fizessem, não há garantia de que eles escapam da mesma maneira.
fonte
A função que eu uso é:
ou seja: eu sempre coloco o argumento entre aspas duplas e depois aspiro com barra invertida os únicos caracteres especiais entre aspas duplas.
fonte
pipes.quote
que o @JohnWiseman apontou também está quebrada. A resposta de Greg Hewgill é, portanto, a única a ser usada. (É também a uma das conchas usar internamente para os casos regulares.)Se você usar o comando system, eu tentaria incluir o que entra na chamada os.system () na lista de permissões. Por exemplo ..
O módulo de subprocesso é uma opção melhor e eu recomendaria tentar evitar usar algo como os.system / subprocess sempre que possível.
fonte
A resposta real é: não use
os.system()
em primeiro lugar. Use emsubprocess.call
vez disso e forneça os argumentos sem escape.fonte