$ VAR vs $ {VAR} e para citar ou não citar

119

Eu posso escrever

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"

o resultado final para mim parece ser o mesmo. Por que eu deveria escrever um ou outro? algum destes não é portátil / POSIX?

    
por xenoterracide 16.12.2010 / 14:14

4 respostas

85

VAR=$VAR1 é uma versão simplificada de VAR=${VAR1} . Há coisas que o segundo pode fazer que o primeiro não pode, por exemplo, referenciar um índice de matriz (não portátil) ou remover uma substring (POSIX-portable). Veja a seção Mais sobre variáveis do Guia de Bash para iniciantes e Expansão do parâmetro na especificação POSIX.

Usar aspas em torno de uma variável como em rm -- "$VAR1" ou rm -- "${VAR}" é uma boa ideia. Isso faz com que o conteúdo da variável seja uma unidade atômica. Se o valor da variável contiver espaços em branco (bem, caracteres na variável $IFS special, espaços em branco por padrão) ou globbing e você não citar, então cada palavra é considerada para geração de nome de arquivo (globbing) cuja expansão faz tantos argumentos para o que você está fazendo.

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

Na portabilidade: De acordo com POSIX.1-2008 seção 2.6.2 , as chaves são opcionais.

    
por 16.12.2010 / 14:38
55

${VAR} e $VAR são exatamente equivalentes. Para uma expansão variável simples, a única razão para usar ${VAR} é quando a análise pegaria muitos caracteres no nome da variável, como em ${VAR1}_$VAR2 (que sem chaves seria equivalente a ${VAR1_}$VAR2 ). A maioria das expansões adornadas ( ${VAR:=default} , ${VAR#prefix} ,…) exigem chaves.

Em uma atribuição de variável, divisão de campo (ou seja, divisão no espaço em branco no valor ) e a expansão do nome do caminho (ou seja, globbing) estão desativadas, então VAR=$VAR1 é exatamente equivalente a VAR="$VAR1" , em todas as shells POSIX e em todas as shs pré-POSIX que eu já ouvi falar. (POSIX ref: comandos simples ). Pelo mesmo motivo, VAR=* define confiavelmente VAR como a string literal * ; É claro que VAR=a b define VAR para a , pois o b é uma palavra separada em primeiro lugar. Em geral, aspas duplas são desnecessárias quando a sintaxe do shell espera uma única palavra, por exemplo case … in (mas não no padrão), mas mesmo assim você precisa ser cuidadoso: por exemplo, o POSIX especifica que alvos de redirecionamento ( >$filename ) não requerem citação em scripts, mas alguns shells, incluindo o bash, exigem aspas duplas, mesmo em scripts. Consulte Quando é necessário fazer uma cotação dupla? para uma avaliação mais completa análise.

Você precisa das aspas duplas em outros casos, em particular em export VAR="${VAR1}" (que pode ser equivalente em export "VAR=${VAR1}" ) em muitos shells (POSIX deixa este caso aberto). A similaridade deste caso com atribuições simples e a natureza dispersa da lista de casos em que você não precisa de aspas duplas, é o motivo pelo qual eu recomendo usar apenas aspas duplas, a menos que você queira dividir e glob.

    
por 16.12.2010 / 19:57
4

Cotação

Considere que as aspas duplas são usadas para expansão de variáveis, e aspas simples são usadas para citações strongs, ou seja, sem expansão.

Expansão:

this='foo'
that='bar'
these="$this"
those='$that'

Saída:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

Pode valer a pena mencionar que você deve usar a cotação sempre que possível por vários motivos, entre os quais os melhores são a melhor prática e a legibilidade. Também porque o Bash é peculiar em alguns momentos e muitas vezes por formas aparentemente ilógicas ou irracionais / inesperadas, e a citação muda as expectativas implícitas para explícitas, o que reduz essa superfície de erro (ou potencial para isso).

E, embora seja completamente legal não citar, e funcionará na maioria dos casos, essa funcionalidade é fornecida por conveniência e é provavelmente menos portável. a prática totalmente formal garantida para refletir intenção e expectativa é citar.

Substituição

Agora, considere também que a construção "${somevar}" é usada para operações de substituição. Vários casos de uso, como substituição e matrizes.

Substituição (remoção):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

Substituição (substituição):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

Matrizes:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

Tudo isso é apenas arranhar a superfície do construtor de substituição "${var}" . A referência definitiva para o shell script Bash é a referência on-line do libre, TLDP The Linux Documentation Project https://www.tldp.org/LDP/abs/html/parameter-substitution.html

    
por 11.02.2018 / 21:10
0
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

final então:

env=$1
    if [ ! -f /dirname/${env}hostname ]

vale a pena mencionar como um exemplo mais claro do uso de curlies

    
por 17.02.2016 / 12:14