Что означает $ # в bash?

У меня есть сценарий в файле с именем instance:

echo "hello world" echo ${1}

И когда я запускаю этот скрипт, используя:

./instance solfish

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

hello world solfish

Но когда я запустил:

echo $#

Он говорит «0». Зачем? Я не понимаю, что означает $#.

Пожалуйста, объясните это.

17
задан 26 July 2017 в 04:10

12 ответов

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

57
ответ дан 22 May 2018 в 20:12
  • 1
    Я думаю, что этот ответ вводит в заблуждение. $ # - максимальный индекс массива аргументов. Если вы дадите один аргумент, это будет доступно в $ 0, а $ # будет иметь значение 0. Если вы дадите два аргумента, они будут в $ 0 и $ 1, а $ # будет иметь значение 1. – JakeRobb 26 July 2017 в 21:41
  • 2
    Кроме того, когда вы используете bash -c, поведение отличается от поведения исполняемого сценария оболочки, поскольку в последнем случае аргумент с индексом 0 является командой оболочки, используемой для ее вызова. Таким образом, я думаю, что способ исправить этот ответ состоит в том, чтобы изменить его на выполнение сценариев в виде файлов вместо использования bash -c, так как так его спрашивал. – JakeRobb 26 July 2017 в 21:46
  • 3
    @JakeRobb Ты меня обманул. Если вы дадите один аргумент, это будет доступно в $ 0, а $ # будет иметь значение 0 - это просто неправильно. – heemayl 27 July 2017 в 15:14
  • 4
    Если вы поместите полную программу, которая смотрит на нее, args на bash -c, вы должны передать bash какое-то содержательное имя в качестве наполнителя для 0-го аргумента. bash -c 'echo "$@"' foo bar печатает только bar, поскольку "$@" не включает $0, как всегда. bash -c не «делает $ 0 одним из аргументов», он просто позволяет вам установить «$ 0», аналогично тому, как вы запускаете программу с системным вызовом execve или любым способом оболочки для переопределения 0-го аргумента. $0 никогда не следует рассматривать как «один из аргументов». – Peter Cordes 27 July 2017 в 15:35
  • 5
    @heemayl в "bash -c" echo $ 0 'foo ", что вы называете" foo " если не аргумент? (Все мое дело здесь в том, что эта ситуация будет вводить в заблуждение неспециалиста, и поэтому требует большего объяснения, чем вы его дали.) – JakeRobb 28 July 2017 в 06:49

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

57
ответ дан 18 July 2018 в 09:42

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

57
ответ дан 24 July 2018 в 19:24

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

У вас их нет, поэтому он выводит 0.

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

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

./instance par1 par2

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

16
ответ дан 22 May 2018 в 20:12
  • 1
    Пример OP: Если вы добавите строку echo $# в свой скрипт и снова запустите ./instance solfish, вы должны получить дополнительную выходную строку с 1, поскольку вы предоставили 1 параметр – derHugo 25 July 2017 в 17:31

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

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

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

Часто # используется в bash для подсчета количества вхождений или длины переменной.

Чтобы найти длину строки:

myvar="some string"; echo ${#myvar}

возвращает: 11

Чтобы найти количество элементов массива:

myArr=(A B C); echo ${#myArr[@]}

возвращает: 3

Чтобы найти длину первого элемента массива:

myArr=(A B C); echo ${#myArr[0]}

возвращает: 1 (Длина A, 0 - первый элемент, поскольку массивы используют индексы / индексы с нулевым основанием).

12
ответ дан 22 May 2018 в 20:12
  • 1
    [F1]? Почему бы не $# -le 0 или эквивалент? – Patrick Trentin 26 July 2017 в 08:37
  • 2
    @PatrickTrentin Потому что я не хочу, чтобы они передавали два или более параметров. Как сказал капитан в «Red October»: «Just One». – WinEunuuchs2Unix 26 July 2017 в 15:53
  • 3
    Затем: «требуется только один аргумент ...». в сообщении об ошибке – Patrick Trentin 26 July 2017 в 16:07
  • 4
    @PatrickTrentin Сообщение об ошибке указывает, как используется сценарий с примером использования одного аргумента. Кроме того, сценарий резервного копирования вызывается cron.daily, который только один раз настраивается специалистом по технологиям: askubuntu.com/questions/917562/… – WinEunuuchs2Unix 26 July 2017 в 16:26
  • 5
    Насколько это важно, я не знаю. Во всяком случае, приветствия. – Patrick Trentin 26 July 2017 в 16:43

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

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

Этот скрипт всегда печатает 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
9
ответ дан 22 May 2018 в 20:12
  • 1
    Престижность для образовательного ответа, который вышел за рамки того, что было задано, но ответил на намерения обучения оригинального асера ​​и других, подобных мне! – Ricardo 10 May 2018 в 21:17

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

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

Этот скрипт всегда печатает 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
9
ответ дан 18 July 2018 в 09:42

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

У вас их нет, поэтому он выводит 0.

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

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

./instance par1 par2

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

16
ответ дан 18 July 2018 в 09:42

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

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

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

Часто # используется в bash для подсчета количества вхождений или длины переменной.

Чтобы найти длину строки:

myvar="some string"; echo ${#myvar}

возвращает: 11

Чтобы найти количество элементов массива:

myArr=(A B C); echo ${#myArr[@]}

возвращает: 3

Чтобы найти длину первого элемента массива:

myArr=(A B C); echo ${#myArr[0]}

возвращает: 1 (Длина A, 0 - первый элемент, поскольку массивы используют индексы / индексы с нулевым основанием).

12
ответ дан 18 July 2018 в 09:42

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

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

Этот скрипт всегда печатает 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
9
ответ дан 24 July 2018 в 19:24
  • 1
    Престижность для образовательного ответа, который вышел за рамки того, что было задано, но ответил на намерения обучения оригинального асера ​​и других, подобных мне! – Ricardo 10 May 2018 в 21:17

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

У вас их нет, поэтому он выводит 0.

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

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

./instance par1 par2

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

16
ответ дан 24 July 2018 в 19:24
  • 1
    Пример OP: Если вы добавите строку echo $# в свой скрипт и снова запустите ./instance solfish, вы должны получить дополнительную выходную строку с 1, поскольку вы предоставили 1 параметр – derHugo 25 July 2017 в 17:31

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

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

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

Часто # используется в bash для подсчета количества вхождений или длины переменной.

Чтобы найти длину строки:

myvar="some string"; echo ${#myvar}

возвращает: 11

Чтобы найти количество элементов массива:

myArr=(A B C); echo ${#myArr[@]}

возвращает: 3

Чтобы найти длину первого элемента массива:

myArr=(A B C); echo ${#myArr[0]}

возвращает: 1 (Длина A, 0 - первый элемент, поскольку массивы используют индексы / индексы с нулевым основанием).

12
ответ дан 24 July 2018 в 19:24
  • 1
    [F1]? Почему бы не $# -le 0 или эквивалент? – Patrick Trentin 26 July 2017 в 08:37
  • 2
    @PatrickTrentin Потому что я не хочу, чтобы они передавали два или более параметров. Как сказал капитан в «Red October»: «Just One». – WinEunuuchs2Unix 26 July 2017 в 15:53
  • 3
    Затем: «требуется только один аргумент ...». в сообщении об ошибке – Patrick Trentin 26 July 2017 в 16:07
  • 4
    @PatrickTrentin Сообщение об ошибке указывает, как используется сценарий с примером использования одного аргумента. Кроме того, сценарий резервного копирования вызывается cron.daily, который только один раз настраивается специалистом по технологиям: askubuntu.com/questions/917562/… – WinEunuuchs2Unix 26 July 2017 в 16:26
  • 5
    Насколько это важно, я не знаю. Во всяком случае, приветствия. – Patrick Trentin 26 July 2017 в 16:43

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

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