Risposta breve: usa"$@"
(nota le doppie virgolette). Le altre forme sono molto raramente utili.
"$@"
è una sintassi piuttosto strana. È sostituito da tutti i parametri posizionali, come campi separati. Se non ci sono parametri posizionali ( $#
è 0), quindi si "$@"
espande a nulla (non una stringa vuota, ma un elenco con 0 elementi), se esiste un parametro posizionale allora "$@"
è equivalente a "$1"
, se ci sono due parametri posizionali allora "$@"
è equivalente a "$1" "$2"
, eccetera.
"$@"
consente di passare gli argomenti di uno script o di una funzione a un altro comando. È molto utile per i wrapper che eseguono operazioni come l'impostazione di variabili di ambiente, la preparazione di file di dati, ecc. Prima di chiamare un comando con gli stessi argomenti e opzioni con cui è stato chiamato il wrapper.
Ad esempio, la seguente funzione filtra l'output di cvs -nq update
. A parte il filtro di output e lo stato di ritorno (che è quello grep
piuttosto che quello di cvs
), chiamare cvssm
alcuni argomenti si comporta come chiamare cvs -nq update
con questi argomenti.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"
si espande nell'elenco dei parametri posizionali. Nelle shell che supportano gli array, esiste una sintassi simile da espandere all'elenco di elementi dell'array: "${array[@]}"
(le parentesi graffe sono obbligatorie tranne in zsh). Ancora una volta, le doppie virgolette sono in qualche modo fuorvianti: proteggono dalla divisione del campo e dalla generazione di schemi degli elementi dell'array, ma ogni elemento dell'array finisce nel suo campo.
Alcune conchiglie antiche avevano probabilmente un bug: quando non c'erano argomenti posizionali, si "$@"
espandevano in un singolo campo contenente una stringa vuota, anziché in nessun campo. Ciò ha portato alla soluzione alternativa${1+"$@"}
(resa famosa dalla documentazione Perl ). Sono interessate solo le versioni precedenti dell'attuale shell Bourne e l'implementazione OSF1, nessuna delle sue moderne sostituzioni compatibili (ash, ksh, bash, ...). /bin/sh
non è influenzato da alcun sistema che è stato rilasciato nel 21 ° secolo di cui sono a conoscenza (a meno che non contiate la versione di manutenzione di Tru64 e anche se /usr/xpg4/bin/sh
è sicuro, quindi #!/bin/sh
sono interessati solo gli script, non gli #!/usr/bin/env sh
script finché il PATH è impostato per la conformità POSIX) . In breve, questo è un aneddoto storico di cui non devi preoccuparti.
"$*"
si espande sempre in una parola. Questa parola contiene i parametri posizionali, concatenati con uno spazio in mezzo. (Più in generale, il separatore è il primo carattere del valore della IFS
variabile. Se il valore di IFS
è la stringa vuota, il separatore è la stringa vuota.) Se non ci sono parametri posizionali, allora "$*"
è la stringa vuota, se ci sono due parametri posizionali e IFS
ha il suo valore predefinito quindi "$*"
è equivalente a "$1 $2"
, ecc.
$@
e le $*
virgolette esterne sono equivalenti. Si espandono all'elenco dei parametri posizionali, come campi separati, come "$@"
; ma ogni campo risultante viene quindi suddiviso in campi separati che vengono trattati come pattern jolly dei nomi di file, come al solito con espansioni variabili non quotate.
Ad esempio, se la directory corrente contiene tre file bar
, baz
e foo
, quindi:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`