web-dev-qa-db-fra.com

$ VAR vs $ {VAR} et pour citer ou ne pas citer

Je peux écrire

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

le résultat final me semble tout à peu près le même. Pourquoi devrais-je écrire l'un ou l'autre? certains d'entre eux ne sont-ils pas portables/POSIX?

150
xenoterracide

VAR=$VAR1 est une version simplifiée de VAR=${VAR1}. Il y a des choses que le second peut faire que le premier ne peut pas, par exemple référencer un index de tableau (non portable) ou supprimer une sous-chaîne (POSIX-portable). Voir la section Plus sur les variables du Bash Guide for Beginners et Expansion des paramètres dans la spécification POSIX.

Utiliser des guillemets autour d'une variable comme dans rm -- "$VAR1" ou rm -- "${VAR}" est une bonne idée. Cela fait du contenu de la variable une unité atomique. Si la valeur de la variable contient des blancs (enfin, les caractères dans le $IFS variable spéciale, espaces par défaut) ou caractères de remplacement et vous ne le citez pas, alors chaque mot est pris en compte pour la génération de nom de fichier (remplacement) dont l'expansion fait autant d'arguments pour ce que vous faites.

$ 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

Sur la portabilité: Selon POSIX.1-2008 section 2.6.2 , les accolades sont facultatives.

108
Shawn J. Goff

${VAR} et $VAR sont exactement équivalents. Pour une expansion de variable simple, la seule raison d'utiliser ${VAR} est lorsque l'analyse aurait autrement pris trop de caractères dans le nom de la variable, comme dans ${VAR1}_$VAR2 (qui sans accolades serait équivalent à ${VAR1_}$VAR2). Extensions les plus ornées (${VAR:=default}, ${VAR#prefix},…) Nécessitent des accolades.

Dans une affectation de variable, fractionnement de champ (c'est-à-dire fractionnement à un espace dans la valeur) et expansion du nom de chemin (c'est-à-dire globalisation) sont désactivés, donc VAR=$VAR1 est exactement équivalent à VAR="$VAR1", dans tous les shells POSIX et dans tous les shells pré-POSIX dont j'ai entendu parler. (Réf POSIX: commandes simples ). Pour la même raison, VAR=* définit de manière fiable VAR sur la chaîne littérale *; bien sûr VAR=a b définit VAR sur a car b est un mot distinct en premier lieu. De manière générale, les guillemets doubles sont inutiles lorsque la syntaxe Shell attend un seul mot, par exemple dans case … in (mais pas dans le modèle), mais même là, vous devez être prudent: par exemple POSIX spécifie que cibles de redirection (>$filename) ne nécessitent pas de guillemets dans les scripts, mais quelques shells dont bash nécessitent les guillemets doubles même dans les scripts. Voir Quand un guillemet double est-il nécessaire? pour une analyse plus approfondie.

Vous avez besoin des guillemets doubles dans d'autres cas, en particulier dans export VAR="${VAR1}" (qui peut s'écrire de manière équivalente export "VAR=${VAR1}") dans de nombreux shells (POSIX laisse ce cas ouvert). La similitude de ce cas avec des affectations simples et la nature dispersée de la liste des cas où vous n'avez pas besoin de guillemets doubles, c'est pourquoi je recommande de simplement utiliser des guillemets doubles à moins que vous ne vouliez diviser et globaliser.

Citation

Considérez que les guillemets doubles sont utilisés pour l'expansion variable et que les guillemets simples sont utilisés pour les guillemets forts, c'est-à-dire sans expansion.

Expansion:

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

Production:

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

Il peut être utile de mentionner que vous devez utiliser la citation dans la mesure du possible pour plusieurs raisons, parmi les meilleures, c'est qu'elle est considérée comme la meilleure pratique et pour la lisibilité. En outre, parce que Bash est parfois décalé et souvent pour des moyens apparemment illogiques ou déraisonnables/inattendus, et la citation modifie les attentes implicites en explicites, ce qui réduit cette surface d'erreur (ou son potentiel).

Et bien qu'il soit tout à fait légal de pas citer, et fonctionnera dans la plupart des cas, cette fonctionnalité est fournie pour plus de commodité et est probablement moins portable. la pratique pleinement formelle garantie de refléter l'intention et l'attente est de citer.

Substitution

Considérons maintenant aussi que la construction "${somevar}" est utilisé pour les opérations de substitution. Plusieurs cas d'utilisation, tels que le remplacement et les tableaux.

Remplacement (décapage):

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

Remplacement (remplacement):

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

Tableaux:

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

Tout cela gratte à peine la surface du "${var}" construction de substitution. La référence définitive pour les scripts Bash Shell est la référence en ligne libre, TLDP The Linux Documentation Project https://www.tldp.org/LDP/abs/html/parameter-substitution.html

9
SYANiDE
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

fin alors:

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

mérite d'être mentionné comme un exemple plus clair d'utilisation de curlies

0
ninjabber