No Bash, ao especificar argumentos de linha de comando para um comando, quais caracteres precisam ser escapados?
Eles são limitados aos metacharacters de Bash: espaço, guia,
|, &, ;, (, ), <, e >?
No Bash, ao especificar argumentos de linha de comando para um comando, quais caracteres precisam ser escapados?
Eles são limitados aos metacharacters de Bash: espaço, guia,
|, &, ;, (, ), <, e >?
Respostas:
Os seguintes caracteres têm um significado especial para o próprio shell em alguns contextos e podem precisar ser ignorados nos argumentos:
` Backtick (U + 0060 Acento grave)~ Tilde (U + 007E)! Ponto de exclamação (U + 0021)# Hash (sinal de número U + 0023)$ Cifrão (U + 0024)& E comercial (U + 0026)* Asterisco (U + 002A)( Parêntese esquerdo (U + 0028)) Parêntese direito (U + 0029) ( ⇥) Guia (U + 0009){ Braçadeira esquerda (U + 007B Suporte esquerdo encaracolado)[ Suporte quadrado esquerdo (U + 005B)| Barra vertical (linha vertical U + 007C)\ Barra invertida (U + 005C Solidus reverso); Ponto e vírgula (U + 003B)' Aspas / Apóstrofo (U + 0027)" Aspas duplas (U + 0022)↩ Nova linha (U + 000A)< Menos que (U + 003C)> Maior que (U + 003E)? Ponto de interrogação (U + 003F) Espaço (U + 0020) 1Alguns desses personagens são usados para mais coisas e em mais lugares do que o que eu vinculei.
Existem alguns casos de canto explicitamente opcionais:
!pode ser desativado com set +H, que é o padrão em shells não interativos.{pode ser desativado com set +B.*e ?pode ser desativado com set -fouset -o noglob .=Sinal de igual (U + 003D) também precisa ser escapado se set -kouset -o keyword está habilitado.Escapar de uma nova linha requer aspas - as barras invertidas não farão o trabalho. Quaisquer outros caracteres listados no IFS precisarão de tratamento semelhante. Você não precisa escapar ]ou }, mas você não precisa escapar )porque é um operador.
Alguns desses personagens têm limites mais rígidos quando realmente precisam escapar do que outros. Por exemplo, a#bestá ok, mas a #bé um comentário, enquanto >precisaria escapar nos dois contextos. De qualquer maneira, não custa escapar de todos eles de maneira conservadora, e é mais fácil do que lembrar as finas distinções.
Se o seu próprio nome de comando é uma palavra-chave shell ( if, for, do), então você precisa escapar ou citá-lo também. O único interessante é que in, porque não é óbvio que é sempre uma palavra-chave. Você não precisa fazer isso para palavras-chave usadas em argumentos, somente quando você (tolamente!) Nomeou um comando após um deles. Os operadores de shell ( (, &etc) sempre precisam citar onde quer que estejam.
1 Stéphane observou que qualquer outro caractere em branco de byte único da sua localidade também precisa ser escapado. Nos locais mais comuns e sensíveis, pelo menos aqueles baseados em C ou UTF-8, são apenas os caracteres de espaço em branco acima. Em alguns locais ISO-8859-1, o espaço sem interrupção U + 00A0 é considerado em branco, incluindo Solaris, BSDs e OS X (penso incorretamente). Se você está lidando com um local desconhecido e arbitrário, ele pode incluir praticamente qualquer coisa, incluindo cartas, então boa sorte.
É possível que um único byte considerado em branco possa aparecer dentro de um caractere de vários bytes que não estivesse em branco, e você não teria como escapar disso além de colocar tudo entre aspas. Isso não é uma preocupação teórica: em um código de idioma ISO-8859-1 a partir de cima, o A0byte que é considerado um espaço em branco pode aparecer dentro de caracteres multibyte como UTF-8 codificado como "à" ( C3 A0). Para lidar com esses caracteres com segurança, você precisará citá-los "à". Esse comportamento depende da configuração do código de idioma no ambiente que está executando o script, não daquele em que você o escreveu.
Eu acho que esse comportamento é quebrado de várias maneiras, mas temos que jogar a mão que recebemos. Se você estiver trabalhando com qualquer conjunto de caracteres multibyte que não seja sincronizado automaticamente, o mais seguro seria citar tudo. Se você estiver em UTF-8 ou C, estará seguro (por enquanto).
!quando a expansão do histórico csh está ativada, normalmente não em scripts. [ ! -f a ]ou find . ! -name...estão bem. Isso é coberto pela seção de limites mais rígidos, mas talvez valha a pena mencionar explicitamente.
hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], os operadores de expressões regulares para [[ x =~ ".+[" ]]. Outras palavras-chave que {( if, while, for...) que precisam ser citado de modo que não é reconhecido como tal ...
]), então não os estou listando. Acho que nenhuma palavra-chave precisa ser citada na posição do argumento.
No GNU Parallel, isso é testado e usado extensivamente:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
Ele é testado em bash, dash, ash, ksh, zsh, e fish. Alguns dos caracteres não precisam ser citados em algumas (versões) dos shells, mas o acima funciona em todos os shells testados.
Se você simplesmente deseja que uma string seja citada, pode inseri-la em parallel --shellquote:
printf "&*\t*!" | parallel --shellquote
Para uma solução de escape leve no Perl, estou seguindo o princípio de aspas simples. Uma cadeia de caracteres Bash entre aspas simples pode ter qualquer caractere, exceto a própria aspas simples.
Meu código:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
Exemplo de execução 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
Exemplo de execução 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
Exemplo de execução 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
Exemplo de execução 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
Exemplo de execução 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c