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 -f
ouset -o noglob
.=
Sinal de igual (U + 003D) também precisa ser escapado se set -k
ouset -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#b
está 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 A0
byte 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