$#
количество аргументов, но помните, что в функции оно будет другим.
$#
это количество позиционных параметров, переданных в скрипт, оболочку или функцию оболочки . Это связано с тем, что во время работы функции оболочки позиционные параметры временно заменяются аргументами функции . Это позволяет функциям принимать и использовать свои собственные позиционные параметры.
Этот скрипт всегда печатает 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
$#
? Чего ты хочешь достичь? Откуда вы взяли эту команду? Это вообще не актуально.