$#
è il numero di argomenti, ma ricorda che sarà diverso in una funzione.
$#
è il numero di parametri posizionali passati alla funzione script, shell o shell . Questo perché, mentre è in esecuzione una funzione shell, i parametri posizionali vengono temporaneamente sostituiti con gli argomenti della funzione . Ciò consente alle funzioni di accettare e utilizzare i propri parametri posizionali.
Questo script viene sempre stampato 3
, indipendentemente dal numero di argomenti passati allo script stesso, poiché "$#"
nella funzione si f
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 della 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
,$#
espande al numero di argomenti passati alla funzione stessa, che in quello script è sempre 0.
Se vuoi tale funzionalità in una funzione shell, dovresti invece scrivere qualcosa del genere:
#!/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 "$#"
Questo funziona perché $#
viene espanso all'esterno della funzione e passato alla funzione come uno dei suoi parametri posizionali. All'interno della funzione, si $1
espande al primo parametro posizionale che è stato passato alla funzione shell, piuttosto che allo script di cui fa parte.
Così, come $#
i parametri speciali $1
, $2
ecc, nonché $@
e $*
, riguardano anche gli argomenti passati ad una funzione, quando vengono espansi nella funzione. Tuttavia, $0
non senza cambiare il nome della funzione, che è il motivo per cui ero ancora in grado di utilizzarlo 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 definisci una funzione all'interno di un'altra, stai 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 averlo eseguito chmod +x nested
) l'ho eseguito:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Si, 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 l' shift
integrato, che sposta ogni parametro posizionale a sinistra di uno, facendo cadere il primo e diminuendo $#
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 il set
builtin:
#!/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
$#
? Cosa vuoi ottenere? Dove hai ricevuto questo comando. Non è per niente rilevante.