$#
to liczba argumentów, ale pamiętaj, że będzie różna w funkcji.
$#
to liczba parametrów pozycyjnych przekazanych do skryptu, powłoki lub funkcji powłoki . Jest tak, ponieważ podczas działania funkcji powłoki parametry pozycyjne są tymczasowo zastępowane argumentami funkcji . Pozwala to funkcjom akceptować i wykorzystywać własne parametry pozycyjne.
Ten skrypt zawsze drukuje 3
, niezależnie od liczby argumentów przekazanych do samego skryptu, ponieważ "$#"
w funkcji f
rozwija się do liczby argumentów przekazanych do funkcji:
#!/bin/sh
f() {
echo "$#"
}
f a b c
Jest to ważne, ponieważ oznacza to, że taki kod nie działa zgodnie z oczekiwaniami, jeśli nie znasz sposobu działania parametrów pozycyjnych w funkcjach powłoki:
#!/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
, $#
rozwija się do liczby argumentów przekazanych samej funkcji, która w tym skrypcie ma zawsze wartość 0.
Jeśli chcesz taką funkcjonalność w funkcji powłoki, musisz zamiast tego napisać coś takiego:
#!/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 "$#"
Działa $#
to, ponieważ jest rozszerzone poza funkcję i przekazane do funkcji jako jeden z jej parametrów pozycyjnych. Wewnątrz funkcji $1
rozwija się do pierwszego parametru pozycyjnego, który został przekazany do funkcji powłoki, a nie do skryptu, którego jest częścią.
Tak więc, jak $#
, specjalne parametry $1
, $2
itp, jak $@
i $*
również odnosić się do argumentów przekazywanych do funkcji, gdy są one w rozbudowanych funkcji. Jednakże, $0
nie nie zmieni się nazwa funkcji, dlatego byłem jeszcze w stanie wykorzystać go do produkcji komunikat o błędzie jakości.
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
Podobnie, jeśli zdefiniujesz jedną funkcję w drugiej, pracujesz z parametrami pozycyjnymi przekazanymi do najbardziej wewnętrznej funkcji, w której przeprowadzane jest rozwinięcie:
#!/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
Wywołałem ten skrypt nested
i (po uruchomieniu chmod +x nested
) uruchomiłem go:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Tak, wiem. „1 argumenty” to błąd pluralizacji.
Parametry pozycyjne można również zmienić.
Jeśli piszesz skrypt, parametrami pozycyjnymi poza funkcją będą argumenty wiersza poleceń przekazywane do skryptu, chyba że je zmieniłeś .
Jednym z powszechnych sposobów ich zmiany jest shift
wbudowane, które przesuwa każdy parametr pozycyjny w lewo o jeden, upuszczając pierwszy i zmniejszając $#
o 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".
Można je również zmienić za pomocą set
wbudowanego:
#!/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
$#
? Co chcesz osiągnąć Skąd masz to polecenie? To w ogóle nie ma znaczenia.