$# è 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 fespande 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 $1espande al primo parametro posizionale che è stato passato alla funzione shell, piuttosto che allo script di cui fa parte.
Così, come $#i parametri speciali $1, $2ecc, nonché $@e $*, riguardano anche gli argomenti passati ad una funzione, quando vengono espansi nella funzione. Tuttavia, $0non 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 nestede (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' shiftintegrato, 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 setbuiltin:
#!/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.