Accedere alla riga di comando bash args $ @ vs $ *


327

In molte domande SO ed esercitazioni bash vedo che posso accedere agli argomenti della riga di comando negli script bash in due modi:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

Che si traduce in:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

Qual è la differenza tra $*e $@?
Quando si dovrebbe usare il primo e quando si dovrebbe usare il secondo?


dare un'occhiata a questa risposta: stackoverflow.com/a/842325/671366
codeling

l'analisi statica in IntelliJ considera echo "something $@"un errore
Alex Cohn,

Risposte:


437

La differenza appare quando vengono citati i parametri speciali. Vorrei illustrare le differenze:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

un ulteriore esempio sull'importanza di citare: nota che ci sono 2 spazi tra "arg" e il numero, ma se non riesco a citare $ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

e in bash, "$@"è l'elenco "predefinito" su cui scorrere:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

65
+1 Ho sempre pensato che questo concetto fosse meglio dimostrato da un semplice esempio, in cui il manuale di bash è completamente carente.
Chepner,

5
Esiste un possibile caso d'uso, quando $*o "$*"potrebbe essere richiesto e lo scopo non può essere servito da $@o "$@"?
anishsane,

5
Quale versione è più adatta per uno script "wrapper", in cui i parametri degli script devono diventare parametri per un nuovo comando?
Segfault,

7
@Segfault, in questo caso, scegli sempre tra "$@"virgolette.
Glenn Jackman,

2
Questa risposta contiene esempi utili, ma sarebbe meglio se spiegasse anche il meccanismo dietro di loro. Perché funziona così?
Lii,

255

Una bella tabella panoramica a portata di mano dal Wiki di Bash Hackers :

$ * contro $ @ tabella

dove cnella terza riga è il primo carattere di $IFS, il separatore di campo interno, una variabile di shell.

Se gli argomenti devono essere memorizzati in una variabile di script e si prevede che gli argomenti contengano spazi, consiglio vivamente di utilizzare un "$*"trucco con il separatore di campo interno $IFSimpostato su tab .


42
... dove "c" è il primo personaggio di $ IFS
glenn jackman,

39
... e $IFSsta per "Separatore di campo interno".
Serge Stroobandt,

Ecco un esempio , che include input tra virgolette. Anche l'input conta!
Serge Stroobandt,

Diciamo che voglio creare uno script wrapper che non fa altro che imitare la funzionalità del comando wrapper. Quale sintassi dovrei usare per passare gli arg dallo script wrapper al comando interno?
Marinos L'

44

$ *

Si espande nei parametri posizionali, a partire da uno. Quando l'espansione avviene tra virgolette doppie, si espande in una singola parola con il valore di ciascun parametro separato dal primo carattere della variabile speciale IFS. Cioè, "$ *" equivale a "$ 1c $ 2c ...", dove c è il primo carattere del valore della variabile IFS. Se IFS non è impostato, i parametri sono separati da spazi. Se IFS è nullo, i parametri vengono uniti senza separatori intervenuti.

$ @

Si espande nei parametri posizionali, a partire da uno. Quando l'espansione avviene tra virgolette doppie, ogni parametro si espande in una parola separata. Cioè, "$ @" equivale a "$ 1" "$ 2" ... Se l'espansione tra virgolette si verifica all'interno di una parola, l'espansione del primo parametro viene unita alla parte iniziale della parola originale e l'espansione dell'ultimo parametro viene unito con l'ultima parte della parola originale. Quando non ci sono parametri posizionali, "$ @" e $ @ si espandono in nulla (cioè vengono rimossi).

Fonte: Bash man


15

$ @ è uguale a $ *, ma ogni parametro è una stringa tra virgolette, ovvero i parametri vengono passati intatti, senza interpretazione o espansione. Ciò significa, tra le altre cose, che ogni parametro nell'elenco degli argomenti è visto come una parola separata.

Ovviamente, "$ @" dovrebbe essere citato.

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST


1

Questo esempio consente di evidenziare la differenza tra "at" e "asterix" mentre li utilizziamo. Ho dichiarato due matrici "frutta" e "verdura"

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

Vedi il seguente risultato il codice sopra:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion

7
Scientificamente parlando, i pomodori sono frutti.
Randy,

1
Hai ragione! "In botanica, un frutto è la struttura portante del seme nelle piante da fiore (noto anche come angiosperme) formata dall'ovaio dopo la fioritura." en.wikipedia.org/wiki/Fruit
stefansson il

@Randy: scientificamente parlando, tutti i frutti sono verdure (è sinonimo di "pianta").
Cris Luengo,

@CrisLuengo eresia! :)
Randy
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.