Вопрос Что означает $ # в bash?


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

echo "hello world"
echo ${1}

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

./instance solfish

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

hello world
solfish

Но когда я бегу:

echo $# 

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

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


17
2017-07-25 14:26


происхождения


Почему вы запускаете $#? Чего вы хотите достичь? Откуда у вас эта команда. Это совсем не актуально. - Pilot6
@ Pilot6 в этом случае он запрашивает значение переменной, это не зависит от конкретного случая, так зачем оператору нужно предоставить эту информацию? - ADDB
@solfish Pilot пытается понять, чего вы ожидаете. Вы сказали, что бежали echo $# и он вернулся 0 что является нормальным. Вы были этому удивлены, но вы не объясняете, чего вы ожидаете, и почему вы были удивлены. Поэтому это поможет нам дать вам лучший ответ, если вы объясните, чего вы ожидаете. Что вы думали, что echo $# сделал бы. Если вы побежали ./instance solfish а также ./instance содержащиеся echo $#, который будет печатать 1 и не 0, - terdon♦
stackoverflow.com/questions/9630203/..., stackoverflow.com/questions/5163144/..., superuser.com/questions/247127/what-is-and-in-linux/247131 - muru
Java также не использует argc. - JakeRobb


ответы:


$# является особой переменной в 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
2017-07-25 14:39



Я думаю, что этот ответ вводит в заблуждение. $ # - максимальный индекс массива аргументов. Если вы дадите один аргумент, это будет доступно в $ 0, а $ # будет иметь значение 0. Если вы дадите два аргумента, они будут в $ 0 и $ 1, а $ # будет иметь значение 1. - JakeRobb
Кроме того, когда вы используете bash -c, поведение отличается от того, если вы запускаете исполняемый сценарий оболочки, потому что в последнем случае аргумент с индексом 0 является командой оболочки, используемой для его вызова. Таким образом, я думаю, что способ исправить этот ответ состоит в том, чтобы изменить его на выполнение сценариев как файлов, а не на использование bash -c, так как это делал аскер. - JakeRobb
@JakeRobb Ты меня обманул. Если вы дадите один аргумент, это будет доступно в $ 0, а $ # будет иметь значение 0 - Это просто неправильно. - heemayl
Если вы поместите полную программу, которая смотрит на нее, bash -c, вы должны пройти bash какое-то значимое имя в качестве наполнителя для 0-го аргумента. bash -c 'echo "$@"' foo bar только печатные издания bar, потому как "$@" не включает $0, как всегда. bash -c не делает «0 $ одним из аргументов», он просто позволяет вам установить «$ 0» так же, как и при запуске программы с помощью execve системный вызов или любой оболочечный способ переопределения 0-го аргумента. $0 никогда не следует считать «одним из аргументов». - Peter Cordes
@heemayl в "bash -c" echo $ 0 'foo ", что вы называете" foo ", если не аргументом? (Все мое дело здесь в том, что эта ситуация будет вводить в заблуждение неспециалиста, и поэтому требует большего объяснения, чем вы его дали.) - JakeRobb


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

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

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

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

./instance par1 par2

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


16
2017-07-25 14:29



Пример OP: Если вы добавите строку echo $# к вашему скрипту и чем снова запустить ./instance solfish вы должны получить дополнительную выходную строку с 1 поскольку вы предоставили 1 параметр - derHugo


$# обычно используется в сценариях 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
2017-07-25 14:44



$# -ne 1? Почему нет $# -le 0 или эквивалент? - Patrick Trentin
@PatrickTrentin Потому что я не хочу, чтобы они передавали два или более параметров. Как сказал капитан в «Красном Октябре»: «Только один». - WinEunuuchs2Unix
Затем: «ровно один аргумент требуется ...» в сообщении об ошибке - Patrick Trentin
@PatrickTrentin Сообщение об ошибке указывает, как используется сценарий с примером использования одного аргумента. Кроме того, сценарий резервного копирования вызывается cron.daily, который только однажды настроен специалистом по технологиям: askubuntu.com/questions/917562/... - WinEunuuchs2Unix
Насколько это важно, я не знаю. Во всяком случае, приветствия. - Patrick Trentin


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

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

Этот скрипт всегда печатает 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 builtin, который сдвигает каждый позиционный параметр слева на один, отбрасывая первый и уменьшая $# на 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
2017-07-25 19:17



Престижность для образовательного ответа, который вышел за рамки того, что было задано, но ответил на намерения обучения оригинального асера ​​и других, подобных мне! - Ricardo