differenza tra $ {} e $ () nello script della shell


Risposte:


39

$(command)è "sostituzione comando". Come sembra capire, esegue il command, cattura il suo output e lo inserisce nella riga di comando che contiene il $(…); per esempio,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}è "sostituzione dei parametri". Molte informazioni sono disponibili nella pagina man della shell, bash (1) , sotto la voce " Espansione dei parametri ":

${parameter}
    Il valore del parametro viene sostituito. Le parentesi graffe sono necessarie quando il parametro è un parametro posizionale con più di una cifra o quando il parametro è seguito da un carattere che non deve essere interpretato come parte del suo nome.

Per i parametri posizionali, vedere " Parametri posizionali ", di seguito. Nel suo utilizzo più comune, come mostrato nelle altre risposte, parameterè un nome variabile. Il ${…}modulo, come indicato alla fine del paragrafo precedente, consente di ottenere il valore di una variabile (ovvero, ) e di seguirlo immediatamente con una lettera, una cifra o un trattino basso:$variable_name

$ animale = cat
$ echo $ animali
                                # Nessuna variabile come "animali".
$ echo $ {animal} s
gatti
$ echo $ animal_food
                                # Nessuna variabile come "animal_food".
$ echo $ {animal} _food
cibo per gatti

Puoi anche farlo con le virgolette:

$ echo "$ animal" s
gatti

Oppure, come esercizio di opzioni, è possibile utilizzare una seconda variabile:

$ plurale = s
$ echo $ animal $ plurale
gatti

Ma questo è solo il passaggio 1. Il prossimo paragrafo nella pagina man è interessante, anche se un po 'enigmatico:

Se il primo carattere del parametro è un punto esclamativo ( !), viene introdotto un livello di indiretta variabile. Bash utilizza il valore della variabile formata dal resto del parametro come nome della variabile; questa variabile viene quindi espansa e quel valore viene utilizzato nel resto della sostituzione, anziché il valore del parametro stesso. Questo è noto come espansione indiretta .     ... (eccezioni) ...    Il punto esclamativo deve seguire immediatamente la parentesi graffa sinistra per introdurre il riferimento indiretto.

Non sono sicuro di come posso renderlo più chiaro se non per esempio:

$ animale = cat
$ echo $ animal
gatto
$ cat = tabby
$ echo $ cat
soriano
$ echo $ {! animal}
tabby                            # Se $ animal è "cat" , allora $ {! animal} è $ cat , ovvero "tabby"

Quindi chiamiamo questo passaggio 1½. Ci sono molte cose interessanti che puoi fare come passaggio 2:

$ animale = cat
$ echo $ {# animal}
3                                # Lunghezza della stringa
$ echo $ {animale / a / ow}
mucca                              # Sostituzione

Non puoi fare nessuna di queste cose senza le {... }parentesi graffe.

Parametri posizionali

Considera questo esempio artificiale :

$ cat myecho.sh
eco $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh Hey diddle diddle, Il gatto e il violino, La mucca saltò sulla luna.
Hey diddle diddle, Il gatto e il violino, The Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

perché la shell non capisce $10, $11ecc Si tratta $10come se fosse ${1}0. Ma capisce ${10}, ${11}ecc., Come menzionato nella pagina man ("un parametro posizionale con più di una cifra").

Ma in realtà non scrivere script del genere; ci sono modi migliori per gestire lunghi elenchi di argomenti.

Quanto sopra (insieme a molte altre forme di costrutti) sono discussi più a fondo nella pagina man della shell, bash (1) .${parameter…something_else}

Una nota sulle citazioni

Nota che dovresti sempre citare le variabili della shell a meno che tu non abbia una buona ragione per non farlo e sei sicuro di sapere cosa stai facendo. Al contrario, sebbene le parentesi graffe possano essere importanti, non sono importanti quanto le virgolette.

$ filename = "nursery rhyme.txt"
$ ls -ld $ {nome file}
ls: impossibile accedere all'asilo: nessun file o directory
ls: impossibile accedere a rhyme.txt: nessun file o directory
$ ls -ld "$ nomefile"
-rwxr-xr-x 1 Noob Noob 5309 2 lug 11:09 nursery rhyme.txt

Ciò vale anche per i parametri posizionali (es. Argomenti della riga di comando; es. "$1") E anche per la sostituzione dei comandi:

$ ls -ld $ (data "+% B% Y"). txt
ls: impossibile accedere a luglio: nessun file o directory
ls: impossibile accedere a 2015.txt: nessun file o directory
$ ls -ld "$ (data" +% B% Y "). txt"
-rwxr-xr-x 1 Noob Noob 687 2 luglio 11:09 luglio 2015.txt

Vedi le citazioni di Bash senza escape sulla sostituzione dei comandi per un breve trattato sull'interazione tra virgolette e $().


grazie per il meraviglioso esempio. Puoi elaborare l'uso di! nel tuo esempio. Non capisco davvero come funzioni.
Noob,

@Noob: OK, ho elaborato l'uso di !.
G-Man dice 'Reinstate Monica' il

Grazie. In qualche modo! Animal si riferisce in realtà alla variabile cat anziché al valore cat. Puoi anche farmi sapere come / diventa una "c" in echo $ {animal / at / ow} La spiegazione dell'uomo di bash è in qualche modo ... non lo so. difficile da capire.
Noob,

inoltre, puoi elaborare questa frase: "$ {parametro} Il valore del parametro viene sostituito." sostituito con cosa? se il parametro è fruit e il suo valore è apple - fruit = apple, quindi $ {fruit} - la mela viene sostituita con ?? non capisco davvero il significato qui sostituito
Noob,

@Noob: "in ${!animal}realtà si riferisce alla variabile $catanziché al valore cat". Sì, questo è esattamente il punto. "Come fa / a diventare una" c "in echo $ {animal / at / ow}?” Eh? / at non diventa "c"; "Cat" diventa "cow" quando "at" è sostituito da "ow".
G-Man dice "Ripristina Monica" il

7

Nel tuo esempio, $ var e $ {var} sono identici. Tuttavia, le parentesi graffe sono utili quando si desidera espandere la variabile in una stringa:

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

Pertanto, le parentesi graffe forniscono un mezzo per sostituire la variabile al fine di ottenere il nome della nuova variabile, che deve essere sostituita.


4

Di solito lo vedo più comunemente nelle stringhe. Qualcosa del genere non funzionerà:

var="a"
echo "$varRAW_STRING"

Ma questo:

var="a"
echo "${var}RAW_STRING"

Come hai detto correttamente, $()viene utilizzato per eseguire un comando:

dir_contents=$(ls)

Puoi anche usare i backtick, ma trovo il $()più versatile. Per prima cosa, i backtick non possono essere (facilmente) nidificati.

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better

In realtà, apici inversi possono essere nidificate: date_directory=`ls \`date '+%Y-%m-%d'\``. Ma è terribilmente brutto; $(…)è molto più chiaro e più facile da usare.
G-Man dice "Ripristina Monica" il

Ok, abbastanza giusto. È tecnicamente possibile, ma non riesco a immaginare nessuno lo faccia mai solo per la leggibilità
bytesized

1
Bene, è `…`stata la (sola) sintassi per la sostituzione del comando per anni prima che $(…)fosse inventata, quindi non è necessario immaginare nulla: la gente l'ha fatto.
G-Man dice "Ripristina Monica" il

lo / lo fa mai / lo fa più /
bytesized
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.