У меня есть сценарий в именованном экземпляре файла:
echo "hello world"
echo ${1}
И когда я выполняю это использование сценария:
./instance solfish
Я получаю этот вывод:
hello world
solfish
Но когда я работаю:
echo $#
Это говорит "0". Почему? Я не понимаю что $#
средства.
Объясните это.
$#
специальная переменная в bash
, это расширяется до количества аргументов (позиционные параметры) т.е. $1, $2 ...
переданный рассматриваемому сценарию или оболочке в случае аргумента непосредственно передал оболочке, например, в bash -c '...' ....
.
Это подобно argc
в C.
Возможно, это прояснит:
$ bash -c 'echo $#'
0
$ bash -c 'echo $#' _ x
1
$ bash -c 'echo $#' _ x y
2
$ bash -c 'echo $#' _ x y z
3
Отметьте это, bash -c
берет аргумент после команды после него запускающийся от 0 ($0
; технически, это справедливо bash
способ позволить Вам установить $0
, не аргумент действительно), таким образом, _
используется здесь в качестве заполнителя; действительные аргументы x
($1
), y
($2
), и z
($3
).
Точно так же в Вашем сценарии (принятие script.sh
) если Вы имеете:
#!/usr/bin/env bash
echo "$#"
Затем, когда Вы делаете:
./script.sh foo bar
сценарий произведет 2; аналогично,
./script.sh foo
произведет 1.
echo $#
производит количество позиционных параметров Вашего сценария.
У Вас нет ни одного, таким образом, это производит 0.
echo $#
полезно в сценарии, не как отдельная команда.
Если Вы запускаете скрипт с некоторыми параметрами как
./instance par1 par2
echo $#
помещенный в сценарий произведет 2.
$#
обычно используется в сценариях удара, чтобы гарантировать, что параметр передается. Обычно Вы проверяете на параметр в начале Вашего сценария.
Например, вот отрывок сценария, я продолжал работать сегодня:
if [[ $# -ne 1 ]]; then
echo 'One argument required for file name, e.g. "Backup-2017-07-25"'
echo '.tar will automatically be added as a file extension'
exit 1
fi
Подводить итог $#
сообщает, что количество параметров передало сценарию. В Вашем случае Вы не передали параметров, и результат, о котором сообщают, 0
.
#
использование в Bash #
часто используется в ударе для подсчета количества случаев или длины переменной.
Найти длину строки:
myvar="some string"; echo ${#myvar}
возвраты: 11
Найти количество элементов массива:
myArr=(A B C); echo ${#myArr[@]}
возвраты: 3
Найти длину первого элемента массива:
myArr=(A B C); echo ${#myArr[0]}
возвраты: 1
(Длина A
, 0 первый элемент, поскольку массивы используют основанные на нуле индексы/нижние индексы).
$#
количество аргументов, но помните, что это будет отличаться в функции.$#
количество позиционных параметров, переданных сценарию, оболочке или функции оболочки. Это вызвано тем, что, в то время как функция оболочки работает, позиционные параметры временно заменяются аргументами функции. Это позволяет функциям принять и использовать свои собственные позиционные параметры.
Этот сценарий всегда печатает 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