$#
è il numero di argomenti, ma ricorda che sarà diverso in una funzione.
$#
è il numero di parametri posizionali passati a script, shell, o funzione shell . Questo perché, mentre una funzione di shell è in esecuzione, i parametri posizionali sono temporaneamente sostituiti con gli argomenti alla funzione . Ciò consente alle funzioni di accettare e utilizzare i propri parametri posizionali.
Questo script stampa sempre 3
, indipendentemente dal numero di argomenti passati allo script stesso, perché "$#"
nella funzione f
si espande al numero di argomenti passati alla funzione:
#!/bin/sh
f() {
echo "$#"
}
f a b c
Questo è importante perché significa che codice come questo non funziona come ci si potrebbe aspettare, se non si ha familiarità con il funzionamento dei parametri posizionali nelle funzioni di shell:
#!/bin/sh
check_args() { # doesn't work!
if [ "$#" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$#" >&2
exit 1
fi
}
# Maybe check some other things...
check_args
# Do other stuff...
In check_args
, $#
si espande al numero di argomenti passati alla funzione stessa, che in quello script è sempre 0.
Se vuoi una funzionalità di questo tipo in una funzione di shell, dovresti scrivere qualcosa come questo:
#!/bin/sh
check_args() { # works -- the caller must pass the number of arguments received
if [ "$1" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$1" >&2
exit 1
fi
}
# Maybe check some other things...
check_args "$#"
Funziona perché $#
è espansa all'esterno della funzione e passata alla funzione come uno dei suoi parametri posizionali. All'interno della funzione, $1
si espande al primo parametro posizionale passato alla funzione shell, piuttosto che allo script di cui fa parte.
Quindi, come $#
, i parametri speciali $1
, $2
, ecc., nonché [email protected]
e $*
, si riferiscono anche agli argomenti passati a una funzione, quando sono espansi in la funzione. Tuttavia, $0
sostituisce non con il nome della funzione, motivo per cui ero ancora in grado di usarlo per produrre un messaggio di errore di qualità.
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
Allo stesso modo, se si definisce una funzione all'interno di un'altra, si sta lavorando con i parametri posizionali passati alla funzione più interna in cui viene eseguita l'espansione:
#!/bin/sh
outer() {
inner() {
printf 'inner() got %d arguments\n' "$#"
}
printf 'outer() got %d arguments\n' "$#"
inner x y z
}
printf 'script got %d arguments\n' "$#"
outer p q
Ho chiamato questo script nested
e (dopo aver eseguito chmod +x nested
) l'ho eseguito:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Sì, lo so. "1 argomenti" è un bug di pluralizzazione.
I parametri posizionali possono anche essere modificati.
Se stai scrivendo uno script, i parametri posizionali all'esterno di una funzione saranno gli argomenti della riga di comando passati allo script a meno che tu non li abbia modificati .
Un modo comune per cambiarli è con shift
incorporato, che sposta ciascun parametro posizionale a sinistra di uno, rilasciando il primo e riducendo $#
di 1:
#!/bin/sh
while [ "$#" -ne 0 ]; do
printf '%d argument(s) remaining.\nGot "%s".\n\n' "$#" "$1"
shift
done
$ ./do-shift foo bar baz # I named the script do-shift.
3 argument(s) remaining.
Got "foo".
2 argument(s) remaining.
Got "bar".
1 argument(s) remaining.
Got "baz".
Possono anche essere modificati con set
incorporato:
#!/bin/sh
printf '%d args: %s\n' "$#" "$*"
set foo bar baz
printf '%d args: %s\n' "$#" "$*"
$ ./set-args a b c d e # I named the script set-args.
5 args: a b c d e
3 args: foo bar baz