Quando abbiamo bisogno di parentesi graffe attorno alle variabili della shell?


659

Negli script di shell, quando utilizziamo {}quando espandiamo le variabili?

Ad esempio, ho visto quanto segue:

var=10        # Declare variable

echo "${var}" # One use of the variable
echo "$var"   # Another use of the variable

C'è una differenza significativa o è solo stile? L'uno è preferito all'altro?

Risposte:


753

In questo esempio particolare, non fa differenza. Tuttavia, {}in ${}sono utili se si desidera espandere la variabile foonella stringa

"${foo}bar"

poiché "$foobar"espanderebbe invece la variabile identificata da foobar.

Le parentesi graffe sono anche necessarie incondizionatamente quando:

  • elementi array in espansione, come in ${array[42]}
  • utilizzando le operazioni di espansione dei parametri, come in ${filename%.*}(rimuovi estensione)
  • espandere i parametri posizionali oltre 9: "$8 $9 ${10} ${11}"

Farlo ovunque, anziché solo in casi potenzialmente ambigui, può essere considerato una buona pratica di programmazione. Questo è sia per coerenza che per evitare sorprese come $foo_$bar.jpg, dove non è visivamente ovvio che il carattere di sottolineatura diventi parte del nome della variabile.


106
{}è noto come espansione di parentesi graffe . ${}è noto come espansione variabile. Fanno cose diverse. Ti voterei ad eccezione del bit di non espansione.
Spencer Rathbun il

5
@NewUser " Quindi, a parte gli array, non è davvero necessario " Non così, le parentesi graffe sono necessarie per PARAMETER EXPANSION , un costrutto molto utile nello scripting. Ho visto molti script sed e awk che possono essere sostituiti con un po 'di espansione dei parametri.
SiegeX,

10
@caffinatedmonkey $()viene utilizzato per eseguire un comando, in modo tale che md5sum=$(md5sum foo.bin)memorizzerà l'output di md5sum foo.binnella variabile md5sum, ora accessibile usando ${md5sum}. Inoltre, +1 e molti altri in spirito all'OP per aver menzionato che è buona prassi essere espliciti!
L0j1k,

11
@ L0j1k Parlando di esplicito, trovo importante menzionare che $()esegue il suo comando da una subshell .
Adrian Günter,

2
@karatedog ${1:-20}è una forma di espansione dei parametri. Qui non è ovvio perché utilizza principalmente cifre e operatori aritmetici che ci inducono a pensare che sia coinvolta l'aritmetica, ma in realtà si riferisce al parametro posizionale $1, che se non definito verrà sostituito da un valore predefinito 20(la sintassi è ${variable:-default_value}).
Aaron,

126

Le variabili sono dichiarate e assegnate senza $e senza {}. Devi usare

var=10

assegnare. Per leggere dalla variabile (in altre parole, 'espandere' la variabile), è necessario utilizzare $.

$var      # use the variable
${var}    # same as above
${var}bar # expand var, and append "bar" too
$varbar   # same as ${varbar}, i.e expand a variable called varbar, if it exists.

Questo a volte mi ha confuso: in altre lingue ci riferiamo alla variabile allo stesso modo, indipendentemente dal fatto che si trovi a sinistra oa destra di un compito. Ma shell-scripting è diverso, $var=10non fa quello che potresti pensare che faccia!


34

Usi {}per raggruppare. Le parentesi graffe sono necessarie per dereferenziare gli elementi dell'array. Esempio:

dir=(*)           # store the contents of the directory into an array
echo "${dir[0]}"  # get the first entry.
echo "$dir[0]"    # incorrect

Non riuscivo a capire la prima riga dir=(*). Per quanto ne so, dirè un comando incorporato per elencare il contenuto della directory (equivalente a ls -C -b). Potresti spiegare per favore?
Jarvis

1
Nella programmazione della shell, i comandi e gli argomenti devono essere separati l'uno dall'altro dagli spazi bianchi. Qui vedi il segno di uguale senza spazi bianchi, il che significa che si tratta di un'assegnazione variabile. dirè il nome della variabile e le parentesi vengono utilizzate per raccogliere l'espansione del nome file *in un array.
Glenn Jackman,

27

Puoi anche fare delle manipolazioni del testo all'interno delle parentesi graffe:

STRING="./folder/subfolder/file.txt"
echo ${STRING} ${STRING%/*/*}

Risultato:

./folder/subfolder/file.txt ./folder

o

STRING="This is a string"
echo ${STRING// /_}

Risultato:

This_is_a_string

Hai ragione in "variabili regolari" non sono necessarie ... Ma è più utile per il debug e leggere uno script.


11

La fine del nome della variabile è generalmente indicata da uno spazio o da una nuova riga. Ma cosa succede se non vogliamo uno spazio o una nuova riga dopo aver stampato il valore della variabile? Le parentesi graffe indicano all'interprete della shell dove si trova la fine del nome della variabile.

Esempio classico 1) - variabile shell senza spazi vuoti finali

TIME=10

# WRONG: no such variable called 'TIMEsecs'
echo "Time taken = $TIMEsecs"

# What we want is $TIME followed by "secs" with no whitespace between the two.
echo "Time taken = ${TIME}secs"

Esempio 2) Percorso di classe Java con vasi con versione

# WRONG - no such variable LATESTVERSION_src
CLASSPATH=hibernate-$LATESTVERSION_src.zip:hibernate_$LATEST_VERSION.jar

# RIGHT
CLASSPATH=hibernate-${LATESTVERSION}_src.zip:hibernate_$LATEST_VERSION.jar

(La risposta di Fred lo afferma già, ma il suo esempio è un po 'troppo astratto)


5

Le parentesi graffe sono sempre necessarie per accedere agli elementi dell'array e per eseguire l'espansione delle parentesi graffe.

È bene non essere troppo cauti e usare {}per l'espansione delle variabili della shell anche quando non c'è spazio per l'ambiguità.

Per esempio:

dir=log
prog=foo
path=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable name
logfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable name
path_copy=${path}             # {} is totally unnecessary
archive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

Quindi, è meglio scrivere le tre righe come:

path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

che è sicuramente più leggibile.

Poiché un nome di variabile non può iniziare con una cifra, la shell non ha bisogno di {}variabili numerate (come $1, $2ecc.) A meno che tale espansione non sia seguita da una cifra. È troppo sottile e fa esplicitamente uso {}in tali contesti:

set app      # set $1 to app
fruit=$1le   # sets fruit to apple, but confusing
fruit=${1}le # sets fruit to apple, makes the intention clear

Vedere:


1
It's good to be not over-cautious: Mi chiedo cosa pensa la maggior parte delle persone. Usa le parentesi graffe per tutto il tempo in modo da non dimenticarle quando sono necessarie o usale solo dove necessario per migliorare la leggibilità.
Roger Dahl,

1
Penso che sia la mancanza di consapevolezza che porta i programmatori a usare i ricci anche quando non sono necessari. Questa ignoranza è simile all'altro errore comune di non usare le doppie virgolette per evitare la divisione o il traboccamento involontario di parole. Alla base di ciò, la realtà è che i programmatori non prendono sul serio gli script di shell tanto quanto altri linguaggi di scripting come Python e Ruby.
codeforester

1
Vero che. La mia idea è che tutti sembrano pensare che tutte le variabili dovrebbero essere tutte maiuscole negli script di shell :)
Roger Dahl

2

Seguendo i suggerimenti di SierraX e Peter sulla manipolazione del testo, {}vengono utilizzate parentesi graffe per passare una variabile a un comando, ad esempio:

Supponiamo che tu abbia un file sposi.txt contenente la prima riga di un noto romanzo italiano:

> sposi="somewhere/myfolder/sposi.txt"
> cat $sposi

ouput: quel ramo del lago di como che volge a mezzogiorno

Ora crea due variabili:

# Search the 2nd word found in the file that "sposi" variable points to
> word=$(cat $sposi | cut -d " " -f 2)

# This variable will replace the word
> new_word="filone"

Ora sostituisci il contenuto della variabile parola con quello di new_word , all'interno del file sposi.txt

> sed -i "s/${word}/${new_word}/g" $sposi
> cat $sposi

ouput: quel filone del lago di como che volge a mezzogiorno

La parola "ramo" è stata sostituita.


1
Funziona altrettanto bene senza parentesi graffe attorno alle variabili.
Armali,

Potresti voler aggiustare il weel-known novelbit. Nominato comunque.
gsl
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.