Devo escapar argumentos shell em Perl?
Pergunta
Ao usar () chamadas em Perl, você tem que escapar do shell args, ou isso é feito automaticamente?
Os argumentos será a entrada do usuário, então eu quero ter certeza que isto não é explorável.
Solução
Se você usar system $cmd, @args
em vez de system "$cmd @args"
(uma matriz em vez de uma string), então você não tem que escapar dos argumentos porque nenhum shell é invocado (veja sistema ). system {$cmd} $cmd, @args
não vai invocar um shell quer mesmo se $ cmd contém metacaracteres e @args está vazia (isto é documentado como parte de exec ). Se os argumentos são provenientes de entrada do usuário (ou outra fonte não confiável), você ainda vai querer untaint eles. Veja -T
no perlrun docs, e perlsec docs.
Se você precisa ler a entrada de saída ou enviar para o comando, qx
e readpipe
não têm equivalente. Em vez disso, o uso open my $output, "-|", $cmd, @args
ou open my $input, "|-", $cmd, @args
embora este não é portátil, pois requer uma fork
real, o que significa Unix única ... Eu acho. Talvez ele vai trabalhar no Windows com seu garfo simulado. A melhor opção é algo como IPC :: Run , que também irá lidar com o caso de tubulação comandos para outros comandos, que nem a forma multi-arg do sistema nem a forma 4 arg de alça será aberta.
Outras dicas
No Windows, a situação é um pouco mais desagradável. Basicamente, todos os programas Win32 receber uma cadeia longa de linha de comando - o shell (geralmente cmd.exe
) pode fazer alguma interpretação primeira, removendo <
e >
redirecionamentos por exemplo, mas ele faz não dividi-lo em palavra limites para o programa. Cada programa deve fazer isso analisar-se (se desejarem - alguns programas não se incomode). Em programas em C e C ++, rotinas fornecidas pelas bibliotecas de tempo de execução fornecidas com o toolchain compilador irá geralmente executar esta etapa de análise antes main()
é chamado.
O problema é, em geral, você não sabe como um determinado programa irá analisar sua linha de comando . Muitos programas são compilados com alguma versão do MSVC ++, cuja peculiar de análise regras são descritas aqui , mas muitos outros são compilados com diferentes compiladores que usam diferentes convenções.
Esta situação é agravada pelo fato de que cmd.exe
tem suas próprias regras peculiar de análise. O acento circunflexo (^
) é tratado como um caractere de escape que cita o caráter seguinte, e de texto dentro de aspas duplas é tratado como citado se uma lista de critérios complicados são satisfeitas (ver cmd /?
para os detalhes completos). Se o seu comando contém quaisquer caracteres estranhos, é muito fácil para a ideia de cmd.exe
de que partes do texto são "citado" e que não estão a sair da sincronia com o seu programa de destino do e ele explodir.
Assim, a abordagem mais segura para escapar argumentos no Windows é:
- argumentos escape da maneira esperada pela linha de comando a análise lógica do programa que você está chamando. (Espero que você sabe o que a lógica é, se não, tente alguns exemplos e acho.)
- Junte-se aos argumentos escaparam com espaços.
- Prefixo cada personagem não alfanumérico da cadeia resultante com
^
. - acrescentar quaisquer redireccionamentos ou outros artifícios escudo (por exemplo, juntando os comandos com
&&
). - Execute o comando com
system()
ou acentos graves.
sub esc_chars {
# will change, for example, a!!a to a\!\!a
@_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;
return @_;
}
http: //www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html
Se você usar o sistema "$ cmd @args" (a string), então você tem que escapar dos argumentos porque um shell é invocado.
Felizmente, para cadeias entre aspas duplas, apenas quatro personagens precisam escapar:
" - double quote
$ - dollar
@ - at symbol
\ - backslash
As respostas sobre a sua pergunta foram muito úteis. No final, eu seguido de @ Runrig conselhos, mas, em seguida, usou o open3 módulo central () de comando para que eu pudesse capturar a saída de STDERR, bem como STDOUT.
Para código de exemplo de open3 () em uso com @ de Runrig solução, ver a minha pergunta e resposta relacionada:
Chamando comandos do sistema de Perl