Por que nós citamos duas vezes uma avaliação de cifrão no Bash? [duplicado]

0

Eu sei que as aspas simples não avaliarão o que está dentro e as aspas duplas. Muitas vezes vejo pessoas citarem a avaliação do cifrão. Aqui estão alguns exemplos:

  • for i in "${indices[@]}"; do
  • if [ "${a}" == 0 ]; then
  • ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4

E se não citarmos duas vezes a expressão do cifrão? AFAIK, o loop for ainda funciona.

    
por Sibbs Gambling 23.02.2017 / 18:28

2 respostas

4

Seus três exemplos não são exatamente iguais.

Nos dois últimos:

if [ "${a}" == 0 ]; then
ffmpeg -framerate 2 -pattern_type glob -i "*.png" -pix_fmt yuv420p output.mp4

Se $a não foi citado e seu valor continha caracteres de $IFS (por espaço padrão, tabulação e nova linha) ou caracteres curinga, isso faça com que [ receba mais de três argumentos (além dos [ e ] ), resultando em um erro; da mesma forma, se o valor de $a fosse a cadeia vazia, isso causaria [ para receber poucos argumentos:

$ (a=0; [ $a == 0 ] && echo OK)
OK

(mas somente se $IFS atualmente não contiver 0 )

$ (a='foo bar'; [ $a == 0 ] && echo OK)
bash: [: too many arguments

(com o valor padrão de $IFS )

$ (a=; [ $a == 0 ] && echo OK)
bash: [: ==: unary operator expected

(mesmo com um $IFS vazio ou com zsh (que, de outra forma, não implementa o operador split + glob implícito em expansões sem aspas))

$ (a='*'; [ $a == 0 ] && echo OK)
bash: [: too many arguments

(quando executado em um diretório que contenha pelo menos dois arquivos não ocultos).

Com cotação, sem erro:

$ (a='foo bar'; [ "$a" == 0 ] && echo OK)
$ (a=; [ "$a" == 0 ] && echo OK)

Seu primeiro exemplo é diferente. As regras sobre expansão dentro as aspas duplas são especiais quando as matrizes estão envolvidas; se a denota um array, então:

  • $a é o primeiro elemento da matriz (em geral, é ${a[0]} , mesmo que o elemento no indice 0 não esteja definido);

  • ${a[*]} ou ${a[@]} são os elementos da matriz, adicionalmente divididos em $IFS (espaço, tabulação, nova linha por padrão);

  • "${a[@]}" são os elementos da matriz, não divididos em $IFS .

Portanto, o seu loop for i in "${indices[@]}"; do ... não funciona o mesmo, dependendo do conteúdo da matriz. Por exemplo:

$ (declare -a a=(a b c); printf '%s\n' $a)
a

$ (declare -a a=(a b c); printf '%s\n' ${a[*]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' ${a[*]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' ${a[@]})
a
b
c

$ (declare -a a=(a 'b c'); printf '%s\n' "${a[*]}")
a b c

$ (declare -a a=(a 'b c'); printf '%s\n' "${a[@]}")
a
b c
    
por 23.02.2017 / 18:52
2

Longa história curta, isso é feito para evitar expansões feitas por caracteres especiais que poderiam estar dentro da variável, como ! . Aspas duplas também são chamadas de "cotação fraca", já que alguns dos caracteres serão interpretados (cifrão, backquote e barra invertida). Aspas simples são "citações strongs" e nada será interpretado.

Citando documentação do bash :

3.1.2.3 Double Quotes

Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, backquote, \, and, when history expansion is enabled, !. When the shell is in POSIX mode (see Bash POSIX Mode), the ! has no special meaning within double quotes, even when history expansion is enabled...

Exemplos de citações fracas e strongs:

  • echo "Your PATH is: $PATH" - Imprimirá Your PATH is:<variable_content>
  • echo 'Your PATH is: $PATH' - Imprimirá Your PATH is: $PATH

Respondendo sua pergunta, usamos aspas duplas com variáveis para permitir que $ seja expandido, mas para evitar que o conteúdo da variável seja expandido ainda mais.

Itens relacionados:

por 23.02.2017 / 18:33