Não se esqueça (possível) nome do arquivo brilhando com * e?
Jeff Schaller
Obrigado. Você poderia listar exaustivamente os tipos de caracteres que precisam ser escapados nos argumentos da linha de cmd?
Tim
É bom ter uma lista, mas a coisa mais importante a entender sobre a citação é: Tudo entre aspas simples é passado literalmente e sem divisão de palavras. Sem exceções. (Isto significa que não há nenhuma maneira que seja para incorporar uma única citação dentro de aspas simples, por sinal, mas isso é fácil de contornar .)
Wildcard
Respostas:
22
Os seguintes caracteres têm um significado especial para o próprio shell em alguns contextos e podem precisar ser ignorados nos argumentos:
=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).
Você só precisa escapar !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.
Stéphane Chazelas
Note que existem contextos onde outros personagens precisam citando como: 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 ...
Stéphane Chazelas
Na medida em que esses são argumentos de linha de comando, a interpretação depende do comando em questão (assim como ]), então não os estou listando. Acho que nenhuma palavra-chave precisa ser citada na posição do argumento.
Michael Homer
2
Citar builtins, traços ou% não faz nada.
Michael Homer
3
No GNU Parallel, isso é testado e usado extensivamente:
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:
Como é que eu não ouvi falar de paralelo antes ...
Tom H
@ TomH Será apreciado se você puder passar 5 minutos pensando em como poderíamos ter chegado até você.
precisa
Eu acho que é um problema de progressão. a maioria das pessoas não precisa ou entende paralelo até progredir em alguns estágios de complexidade. Quando eles já se deparam com xargs, nohup e coisas assim. Também não vejo muitas pessoas usando paralelo para resolver problemas na troca de pilhas ou quando busco soluções para resolver problemas
Tom H
1
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 $_;}}
Sim, ponto válido que. Minha opinião é que a maioria das pessoas chegará a esta página porque tem um problema a resolver. Não porque isso faz um debate acadêmico interessante. É por isso que eu gostaria de oferecer soluções e discutir os méritos delas, mesmo estando um pouco fora de tópico.
precisa saber é o seguinte
Meu código é apenas uma implementação da resposta de Michael Homer. Não pretendia trazer mais informações do que o que ele fez.
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) 1
Alguns 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 comset +H
, que é o padrão em shells não interativos.{
pode ser desativado comset +B
.*
e?
pode ser desativado comset -f
ouset -o noglob
.=
Sinal de igual (U + 003D) também precisa ser escapado seset -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, masa #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 é quein
, 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).
fonte
!
quando a expansão do histórico csh está ativada, normalmente não em scripts.[ ! -f a ]
oufind . ! -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:
Ele é testado em
bash
,dash
,ash
,ksh
,zsh
, efish
. 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
:fonte
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:
Exemplo de execução 1:
Exemplo de execução 2:
Exemplo de execução 3:
Exemplo de execução 4:
Exemplo de execução 5:
fonte