Qual é a diferença de ter aspas duplas ou não no bash [duplicado]

8

Eu tenho alguns scripts bash, um deles com o seguinte conteúdo:

#!/bin/bash
source $(dirname ${BASH_SOURCE[0]})/script.sh

enquanto o outro tem o seguinte conteúdo:

#!/bin/bash
source "$(dirname ${BASH_SOURCE[0]})/script.sh"

Como esses scripts se comportam de maneira diferente e por quê? O que é a diferença?

    
por Alex 14.04.2014 / 08:56

3 respostas

7

A principal diferença é que a versão citada não está sujeita à divisão de campo pelo shell.

Com aspas duplas, o resultado da expansão de comando seria alimentado como um parâmetro para o comando source . Sem aspas, ele seria dividido em vários parâmetros, dependendo do valor de IFS que contém espaço, TAB e nova linha por padrão.

Se o nome do diretório não contiver tais espaços, a divisão de campos não ocorrerá.

Como regra geral, é melhor usar aspas duplas com substituições de comandos e expansões variáveis.

    
por 14.04.2014 / 09:05
12

Sem aspas, a string está sujeita a divisão de palavras e globbing . Veja também BashPitfalls # 14 .

Compare

$ echo $(printf 'foo\nbar\nquux\n*')
foo bar quux ssh-13yzvBMwVYgn ssh-3JIxkphQ07Ei ssh-6YC5dbnk1wOc 

com

$ echo "$(printf 'foo\nbar\nquux\n*')"
foo
bar
quux
*

Quando a divisão de palavras ocorre, o primeiro caractere de IFS age como um separador (que, por padrão, é um espaço).

Em quase todas as situações, você deseja adicionar cotações. Existem algumas exceções, por exemplo,

  • Em expressões em que a divisão / globulação de palavras não ocorre, por exemplo, atribuições simples (não-matriz) e a instrução case . Os seguintes são todos seguros:

    • foo=*
    • foo=${bar}qux${quux}
    • foo=$(bar "${quux}")
    • case ${var} in

    Isso, no entanto, não é (se o que você está procurando for um único elemento com um caractere de asterisco literal):

    • foo=( * )
  • Quando você deseja especificamente que a divisão de palavras ocorra, por exemplo, looping sobre os tokens em uma string delimitada por espaço em branco (com globbing desativado). No entanto, se possível, use uma matriz.

por 14.04.2014 / 09:23
4

A provável diferença mais importante seria se o diretório em que o script está continha um espaço. Nesse caso, a primeira linha, a que não continha aspas duplas, falharia. Isso seria o resultado da "divisão de palavras" que o bash faz em strings não citadas.

Suponha que o resultado de dirname ${BASH_SOURCE[0]} seja /home/j r/bin . Considere a linha sem aspas:

source $(dirname ${BASH_SOURCE[0]})/script.sh

Neste caso, o bash verá o comando:

source /home/j r/bin/script.sh

Após a divisão de palavras, o comando source vê um nome de script, /home/j e um argumento para o script, r/bin/script.sh . Muito provavelmente, não há script com esse nome e o bash retornará a mensagem de erro:

bash: /bin/j: No such file or directory

Agora, considere o que acontece com aspas duplas:

source "$(dirname ${BASH_SOURCE[0]})/script.sh"

Nesse caso, o comando source procurará um script chamado /home/j r/bin/script.sh e tentará originá-lo.

Para completar, vamos considerar aspas simples:

source '$(dirname ${BASH_SOURCE[0]})/script.sh'

Neste caso, ao contrário dos dois anteriores, dirname nunca é executado. O comando source tentará originar um comando com o nome literal $(dirname ${BASH_SOURCE[0]})/script.sh . Provavelmente não existe tal arquivo e o bash emitirá uma mensagem de erro.

Como o bash trata strings entre aspas duplas é descrito detalhadamente em man bash :

  Enclosing characters in double quotes preserves the  literal  value  of
   all  characters  within the quotes, with the exception of $, ', \, and,
   when history expansion is enabled, !.  The characters $  and  '  retain
   their  special meaning within double quotes.  The backslash retains its
   special meaning only when followed by one of the following  characters:
   $,  ',  ", \, or <newline>.  A double quote may be quoted within double
   quotes by preceding it with a backslash.  If enabled, history expansion
   will  be  performed  unless an !  appearing in double quotes is escaped
   using a backslash.  The backslash preceding the !  is not removed.
    
por 14.04.2014 / 09:08