Referenciando Variáveis ​​em um Script de Shell

10

Em um script de shell, se eu definir uma variável como FOO=25, existe uma diferença entre referenciá-la como $FOO$e ${FOO}$?

Karnivaurus
fonte
2
Você não deve usar o $no final! Será tratado como caractere normal e não como parte do nome da variável.
Byte Commander

Respostas:

16

Na maioria das situações, tanto $vare ${var}são os mesmos. (Observe que você não deve usar um $no final!)

Um exemplo em que você precisa de chaves é quando você precisa colocar uma variável em uma sequência contínua.

Exemplo:

var=hel
echo ${var}lo

será exibido hello.

Aizuddin Zali
fonte
11

Para responder à sua pergunta principal, ${foo}é chamado de "expansão de parâmetros" . Para ser mais preciso, o $próprio inicia a expansão do parâmetro, na { }verdade é opcional de acordo com a especificação POSIX , mas pode ser útil para indicar o final do nome da variável:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

Basicamente, $fooe ${foo}são idênticos. Além de casos como o descrito acima ou quando você está manipulando strings , eles são completamente equivalentes.

No entanto, você realmente não deve usar nenhum deles. A regra geral é que, com muito poucas exceções, você deve sempre usar "$foo"or "${foo}"e never $fooor ${foo}. Você deve sempre citar suas variáveis ​​para evitar chamar o operador split + glob (mais sobre isso mais tarde). Você certamente não quer $foo$. A final $é irrelevante:

$ foo="bar"
$ echo "$foo$"
bar$

Portanto, embora as variáveis ​​não citadas às vezes sejam OK:

$ echo $foo
bar

Geralmente não são e devem ser realmente evitados:

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Observe que os colchetes também não ajudam aqui:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Quando você usa $fooou ${foo}, o shell divide o valor salvo na variável no espaço em branco (isso pode ser alterado definindo a IFSvariável para outra coisa) em uma lista e, em seguida, cada elemento da lista é tratado como um padrão global e expandido para quaisquer arquivos ou diretórios correspondentes. Isso é conhecido como operador split + glob . Para ilustrar, considere um diretório com dois arquivos:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

Agora, vamos definir uma variável para foo *:

$ foo="foo *"

O que acontece se tentarmos verificar se existe um arquivo com esse nome?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

A variável foi dividida em fooe *e, uma vez que *é um curinga que corresponde a qualquer cadeia, o shell diz que um arquivo chamado foo *exxists. No entanto, se citá-lo corretamente, isso não acontece:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

Esse foi um exemplo trivial para ilustrar o ponto. Imagine se eu tivesse usado em rmvez disso echo.

Então, primeira regra: sempre cite suas variáveis. Você pode usar um "$foo"ou outro, "${foo}"mas citá-lo de qualquer maneira. Para obter mais detalhes sobre o uso de variáveis ​​com segurança, consulte estas postagens:

Terdon
fonte
Eu não queria editar o seu caso contrário excelente resposta, mas não deve $ var="foo *"ser $ foo="foo *"? Você não usa em varlugar algum.
21415 Joe
@ Joe oh, que pena! Sim, claro que deveria, obrigado por apontar. Sinta-se livre para corrigir esses erros, sugerindo uma edição, a propósito. Esse tipo de coisa é muito incentivado, precisamente para evitar erros tolos como este.
terdon