È iniziato come un trucco nella shell Bourne. Nella shell Bourne, la divisione delle parole IFS è stata eseguita (dopo la tokenizzazione) su tutte le parole nel contesto dell'elenco (argomenti della riga di comando o le parole su cui si ripetono i for
loop). Se tu avessi:
IFS=i var=file2.txt
edit file.txt $var
Questa seconda linea sarebbe tokenised in 3 parole, $var
sarebbe stato ampliato, e dividere + glob sarebbe stato fatto su tutte e tre le parole, così si finirebbe in esecuzione ed
con t
, f
, le.txt
, f
, le2.txt
come argomenti.
La citazione di parti di ciò impedirebbe la divisione + glob. La shell Bourne inizialmente ricordava quali personaggi venivano citati impostando internamente l'ottavo bit (che cambiò più tardi quando Unix divenne pulito a 8 bit, ma la shell fece ancora qualcosa di simile per ricordare quale byte era citato).
Entrambi $*
e $@
sono stati la concatenazione dei parametri posizionali con spazio in mezzo. Ma c'è stata un'elaborazione speciale di $@
quando all'interno delle doppie virgolette. Se $1
contenuto foo bar
e $2
contenuto baz
, "$@"
si espanderebbe in:
foo bar baz
^^^^^^^ ^^^
(con la ^
s sopra che indica quale dei personaggi ha l'ottavo bit impostato). Dove è stato citato il primo spazio (con l'ottavo bit impostato) ma non il secondo (quello aggiunto tra le parole).
Ed è la suddivisione IFS che si occupa di separare gli argomenti (supponendo che il carattere dello spazio sia $IFS
come è di default). È simile a come è $*
stato ampliato nel suo predecessore la shell Mashey (a sua volta basata sulla shell Thomson, mentre la shell Bourne è stata scritta da zero).
Questo spiega perché nella shell Bourne inizialmente si "$@"
sarebbe espanso nella stringa vuota invece di nulla quando l'elenco dei parametri posizionali era vuoto (con cui si doveva aggirare ${1+"$@"}
), perché non manteneva i parametri posizionali vuoti e perché "$@"
non non funziona quando $IFS
non contiene il carattere spaziale.
L'intenzione era quella di essere in grado di passare la lista di argomenti alla lettera ad un altro comando, ma che non funzionava correttamente per la lista vuota, per gli elementi vuoti o quando $IFS
non conteneva spazio (i primi due problemi furono infine risolti nelle versioni successive ).
La shell Korn (su cui si basa la specifica POSIX) ha modificato questo comportamento in alcuni modi:
- La suddivisione IFS viene eseguita solo sul risultato di espansioni non quotate (non su parole letterali come
edit
o file.txt
nell'esempio sopra)
$*
e $@
vengono uniti con il primo carattere $IFS
o spazio quando $IFS
è vuoto tranne quello per un quotato "$@"
, quel joiner non è citato come nella shell Bourne, e per un quotato "$*"
quando IFS
è vuoto, i parametri posizionali vengono aggiunti senza separatore.
- ha aggiunto il supporto per gli array, e con
${array[@]}
${array[*]}
reminiscenze di Bourne $*
e $@
ma a partire dall'indice 0 invece di 1, e scarso (più simile agli array associativi) il che significa che $@
non può davvero essere trattato come un array ksh (confronta con csh
/ rc
/ zsh
/ fish
/ yash
dove $argv
/ $*
sono normali array).
- Gli elementi vuoti vengono conservati.
"$@"
quando $#
è 0 ora si espande nel nulla anziché nella stringa vuota, "$@"
funziona quando $IFS
non contiene spazi tranne quando IFS
è vuoto. Un non quotato $*
senza caratteri jolly si espande in un argomento (in cui i parametri posizionali sono uniti con lo spazio) quando $IFS
è vuoto.
ksh93 risolto i restanti pochi problemi sopra. In ksh93, $*
e si $@
espande all'elenco dei parametri posizionali, separato indipendentemente dal valore di $IFS
, e quindi ulteriormente diviso + globbed + parentesi espansa nei contesti di elenco, $*
unito al primo byte (non carattere) di $IFS
, "$@"
nei contesti di elenco si espande all'elenco dei parametri posizionali, indipendentemente dal valore di $IFS
. In un contesto non di elenco, come in var=$@
, $@
viene unito con spazio indipendentemente dal valore di $IFS
.
bash
Le matrici sono progettate dopo quelle ksh. Le differenze sono:
- nessuna parentesi graffa-espandi in caso di espansione non quotata
- primo carattere di
$IFS
anziché di byte
- alcune differenze di maiuscole / minuscole come l'espansione di
$*
quando non quotato in un contesto non di elenco quando $IFS
è vuoto.
Mentre le specifiche POSIX erano piuttosto vaghe, ora specifica più o meno il comportamento bash.
È diverso dalle normali matrici in ksh
o bash
in quella:
- Gli indici iniziano da 1 invece di 0 (tranne in
"${@:0}"
cui include $0
(non un parametro posizionale, e nelle funzioni ti dà il nome della funzione o meno a seconda della shell e di come è stata definita la funzione)).
- Non puoi assegnare elementi singolarmente
- non è scarso, non puoi disinserire gli elementi singolarmente
shift
può essere utilizzato.
In zsh
o yash
dove gli array sono array normali (non sparsi, gli indici iniziano da uno come in tutti gli altri shell ma ksh / bash), $*
viene trattato come un array normale. zsh
ha $argv
come alias per esso (per compatibilità con csh
). $*
è lo stesso di $argv
o ${argv[*]}
(argomenti uniti al primo carattere di $IFS
ma ancora separati in contesti di lista). "$@"
come "${argv[@]}"
o "${*[@]}"}
subisce la speciale elaborazione in stile Korn.