bash で $# はどういう意味ですか?

bash で $# はどういう意味ですか?

インスタンスという名前のファイルにスクリプトがあります:

echo "hello world"
echo ${1}

そして、このスクリプトを次のように実行します:

./instance solfish

次のような出力が得られます:

hello world
solfish

しかし、実行すると:

echo $# 

「0」と表示されています。なぜですか? 意味がわかりません$#

説明してください。

答え1

$#は 内の特殊変数で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$1y$2z$3


同様に、スクリプトでは( と仮定してscript.sh)、次のようになります。

#!/usr/bin/env bash
echo "$#"

次に、次の操作を実行します。

./script.sh foo bar

スクリプトは2を出力します。同様に、

./script.sh foo

1 を出力します。

答え2

echo $#スクリプトの位置パラメータの数を出力します。

何もないので、0 が出力されます。

echo $#個別のコマンドとしてではなく、スクリプト内で役立ちます。

次のようなパラメータを指定してスクリプトを実行すると、

./instance par1 par2

echo $#スクリプト内に配置されたものは2 を出力します。

答え3

$#は、通常、bash スクリプトでパラメータが渡されることを確認するために使用されます。一般的に、スクリプトの先頭でパラメータをチェックします。

たとえば、今日私が作業していたスクリプトの一部を以下に示します。

if [[ $# -ne 1 ]]; then
    echo 'One argument required for the 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 は最初の要素です)。

答え4

$#は引数の数ですが、関数では異なることに注意してください。

$#スクリプト、シェルに渡される位置パラメータの数です。またはシェル関数これは、シェル関数の実行中に、位置パラメータは関数の引数に一時的に置き換えられますこれにより、関数は独自の位置パラメータを受け入れて使用できるようになります。

このスクリプトは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 引数」は複数形化のバグです。

位置パラメータも変更できます。

スクリプトを書いている場合、関数外の位置パラメータはスクリプトに渡されるコマンドライン引数になります。変更しない限り

これらを変更する一般的な方法の 1 つは、shift組み込み関数を使用することです。組み込み関数は、各位置パラメータを 1 つ左にシフトし、最初のパラメータを削除して$#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

関連情報