Что делает $ #, означают в ударе?

У меня есть сценарий в именованном экземпляре файла:

echo "hello world"
echo ${1}

И когда я выполняю это использование сценария:

./instance solfish

Я получаю этот вывод:

hello world
solfish

Но когда я работаю:

echo $# 

Это говорит "0". Почему? Я не понимаю что $# средства.

Объясните это.

25
задан 25 July 2017 в 18:10

4 ответа

$# специальная переменная в 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.

66
ответ дан 23 November 2019 в 01:10

echo $# производит количество позиционных параметров Вашего сценария.

У Вас нет ни одного, таким образом, это производит 0.

echo $# полезно в сценарии, не как отдельная команда.

Если Вы запускаете скрипт с некоторыми параметрами как

./instance par1 par2

echo $# помещенный в сценарий произведет 2.

17
ответ дан 23 November 2019 в 01:10

$# обычно используется в сценариях удара, чтобы гарантировать, что параметр передается. Обычно Вы проверяете на параметр в начале Вашего сценария.

Например, вот отрывок сценария, я продолжал работать сегодня:

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 первый элемент, поскольку массивы используют основанные на нуле индексы/нижние индексы).

13
ответ дан 23 November 2019 в 01:10

$# количество аргументов, но помните, что это будет отличаться в функции.

$# количество позиционных параметров, переданных сценарию, оболочке или функции оболочки. Это вызвано тем, что, в то время как функция оболочки работает, позиционные параметры временно заменяются аргументами функции. Это позволяет функциям принять и использовать свои собственные позиционные параметры.

Этот сценарий всегда печатает 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
10
ответ дан 23 November 2019 в 01:10

Другие вопросы по тегам:

Похожие вопросы: