$#
は引数の数ですが、関数では異なることに注意してください。
$#
は、スクリプト、シェル、またはシェル関数に渡される位置パラメーターの数です。これは、シェル関数の実行中に、位置パラメーターが一時的に関数の引数に置き換えられるためです。これにより、関数は独自の定位置パラメーターを受け入れて使用できます。
このスクリプトは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
$#
?何を達成したいですか?このコマンドはどこで入手しましたか。それはまったく関係ありません。