Primeiro, separe o zsh do resto. Não se trata de conchas antigas e modernas: o zsh se comporta de maneira diferente. Os designers do zsh decidiram torná-lo incompatível com os shells tradicionais (Bourne, ksh, bash), mas mais fáceis de usar.
Segundo, é muito mais fácil usar aspas duplas o tempo todo do que lembrar quando elas são necessárias. Eles são necessários na maioria das vezes, portanto, você precisará aprender quando não forem necessários, não quando forem necessários.
Em poucas palavras, aspas duplas são necessárias sempre que uma lista de palavras ou um padrão é esperado . Eles são opcionais em contextos em que uma sequência bruta é esperada pelo analisador.
O que acontece sem aspas
Observe que, sem aspas duplas, duas coisas acontecem.
- Primeiro, o resultado da expansão (o valor da variável para uma substituição de parâmetro como
${foo}
, ou a saída do comando para uma substituição de comando como $(foo)
) é dividido em palavras onde quer que haja espaço em branco.
Mais precisamente, o resultado da expansão é dividido em cada caractere que aparece no valor da IFS
variável (caractere separador). Se uma sequência de caracteres separadores contiver espaços em branco (espaço, tabulação ou nova linha), o espaço em branco será contabilizado como um único caractere; separadores à esquerda, à esquerda ou repetidos em branco não levam a campos vazios. Por exemplo, with IFS=" :"
, :one::two : three: :four
produz campos vazios antes one
, entre one
e two
, e (um único) entre three
e four
.
- Cada campo resultante da divisão é interpretado como um glob (um padrão curinga) se ele contiver um dos caracteres
\[*?
. Se esse padrão corresponder a um ou mais nomes de arquivos, o padrão será substituído pela lista de nomes de arquivos correspondentes.
Uma expansão de variável não citada $foo
é conhecida coloquialmente como "operador split + glob", em contraste com o "$foo"
qual apenas assume o valor da variável foo
. O mesmo vale para substituição de comando: "$(foo)"
é uma substituição de comando, $(foo)
é uma substituição de comando seguida por split + glob.
Onde você pode omitir as aspas duplas
Aqui estão todos os casos em que posso pensar em um shell no estilo Bourne, no qual você pode escrever uma substituição de variável ou comando sem aspas duplas, e o valor é interpretado literalmente.
No lado direito de uma tarefa.
var=$stuff
a_single_star=*
Observe que você precisa de aspas duplas depois export
, porque é um builtin comum, não uma palavra-chave. Isso é verdade apenas em alguns shells, como dash, zsh (emulação sh), yash ou chique; o bash e o ksh tratam export
especialmente.
export VAR="$stuff"
Em uma case
declaração.
case $var in …
Observe que você precisa de aspas duplas em um padrão de caso. A divisão de palavras não ocorre em um padrão de maiúsculas e minúsculas, mas uma variável entre aspas é interpretada como um padrão, enquanto uma variável entre aspas é interpretada como uma sequência literal.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
Dentro de colchetes duplos. Parênteses duplos são sintaxe especial do shell.
[[ -e $filename ]]
Exceto que você precisa de aspas duplas onde é esperado um padrão ou expressão regular: no lado direito de =
ou ==
ou !=
ou =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
Você precisa de aspas duplas, como de costume, entre colchetes, [ … ]
porque elas são sintaxe comum do shell (é um comando que é chamado [
). Consulte Parênteses simples ou duplos
Em um redirecionamento em shells POSIX não interativos (não bash
, nem ksh88
).
echo "hello world" >$filename
Algumas shells, quando interativas, tratam o valor da variável como um padrão curinga. O POSIX proíbe esse comportamento em shells não interativos, mas alguns shells, incluindo o bash (exceto no modo POSIX) e o ksh88 (inclusive quando encontrado como o (supostamente) POSIX sh
de alguns Unices comerciais como o Solaris) ainda o fazem lá ( bash
também tentam dividir e o redirecionamento falhará, a menos que a divisão + oclusão resulte em exatamente uma palavra), e é por isso que é melhor citar destinos de redirecionamentos em um sh
script, caso você queira convertê-lo em um bash
script algum dia ou executá-lo em um sistema onde sh
está não compatível nesse ponto ou pode ser proveniente de shells interativos.
Dentro de uma expressão aritmética. De fato, você precisa deixar as aspas para que uma variável seja analisada como uma expressão aritmética.
expr=2*2
echo "$(($expr))"
No entanto, você precisa das aspas em torno da expansão aritmética, pois elas estão sujeitas à divisão de palavras na maioria dos shells, conforme o POSIX exige (!?).
Em uma matriz associativa subscrita.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
Uma variável não citada e substituição de comando podem ser úteis em algumas circunstâncias raras:
- Quando o valor da variável ou a saída do comando consiste em uma lista de padrões globais e você deseja expandir esses padrões para a lista de arquivos correspondentes.
- Quando você sabe que o valor não contém nenhum caractere curinga, isso
$IFS
não foi modificado e você deseja dividi-lo em caracteres de espaço em branco.
- Quando você deseja dividir um valor em um determinado caractere: desative o globbing com
set -f
, defina IFS
o caractere separador (ou deixe em branco para dividir no espaço em branco) e faça a expansão.
Zsh
No zsh, você pode omitir as aspas duplas na maioria das vezes, com algumas exceções.
$var
nunca se expande para várias palavras, no entanto, se expande para a lista vazia (em oposição a uma lista que contém uma única palavra vazia) se o valor de var
for a sequência vazia. Contraste:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
Da mesma forma, se "${array[@]}"
expande para todos os elementos da matriz, enquanto se $array
expande apenas para os elementos não vazios.
A @
bandeira de expansão de parâmetros, por vezes, requer aspas em torno toda a substituição: "${(@)foo}"
.
A substituição de comando sofre divisão de campo se não estiver entre aspas: echo $(echo 'a'; echo '*')
imprime a *
(com um único espaço) enquanto echo "$(echo 'a'; echo '*')"
imprime a sequência de duas linhas não modificada. Use "$(somecommand)"
para obter a saída do comando em uma única palavra, sem novas linhas finais. Use "${$(somecommand; echo _)%?}"
para obter a saída exata do comando, incluindo novas linhas finais. Use "${(@f)$(somecommand)}"
para obter uma matriz de linhas da saída do comando.
SH_WORD_SPLIT
opção.