$#
- кількість аргументів, але пам’ятайте, що вона буде відрізнятися у функції.
$#
- кількість позиційних параметрів, переданих функції скрипту, оболонки або оболонки . Це тому, що, поки функція оболонки виконується, позиційні параметри тимчасово замінюються аргументами функції . Це дозволяє функціям приймати та використовувати власні позиційні параметри.
Цей скрипт завжди друкується 3
, незалежно від того, скільки аргументів було передано самому сценарію, оскільки "$#"
в функції f
розширюється кількість аргументів, переданих функції:
#!/bin/sh
f() {
echo "$#"
}
f a b c
Це важливо, оскільки це означає, що такий код не працює, як ви могли очікувати, якщо ви не знайомі з тим, як працюють позиційні параметри в оболонках:
#!/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...
В check_args
,$#
розширюється на кількість аргументів, переданих самій функції, яка в цьому сценарії завжди дорівнює 0.
Якщо вам потрібна така функціональність у функції оболонки, вам доведеться замість цього написати щось подібне:
#!/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 "$#"
Це працює, тому що $#
розширено поза функцією та передана функції як один із її позиційних параметрів. Всередині функції $1
розширюється на перший позиційний параметр, який був переданий функції оболонки, а не до сценарію, до складу якого входить.
Таким чином, як $#
, спеціальні параметри $1
, $2
і т.д., а також $@
і $*
, також відносяться до аргументів , переданих функції, коли вони розкладаються в функції. Однак $0
це не змінюється на назві функції, саме тому мені все ж вдалося використовувати її для створення повідомлення про помилку якості.
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
Аналогічно, якщо ви визначаєте одну функцію всередині іншої, ви працюєте з позиційними параметрами, переданими до найпотаємнішої функції, в якій виконується розширення:
#!/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
Я назвав цей сценарій nested
і (після запуску chmod +x nested
) запустив його:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Так, я знаю. "1 аргумент" - помилка плюралізації.
Параметри позиції також можуть бути змінені.
Якщо ви пишете скрипт, позиційні параметри поза функцією будуть аргументами командного рядка, переданими до сценарію, якщо ви їх не змінили .
Один із поширених способів їх зміни - це shift
вбудований, який зміщує кожен позиційний параметр вліво на один, опускаючи перший і зменшуючи $#
на 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".
Їх також можна змінити за допомогою set
вбудованого:
#!/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
$#
? Чого ти хочеш досягти? Звідки ви взяли цю команду. Це зовсім не актуально.