
f
私は以下に基づいてBashで関数を定義しました:ここの例(「パラメータのあるオプション」の下):
f () {
while getopts ":a:" opt; do
case $opt in
a)
echo "-a was triggered, Parameter: $OPTARG" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
return 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
return 1
;;
esac
done
}
彼らはスクリプトを使用していますが、私はシェルから直接関数を定義します。
Bashを初めて起動して次の関数を定義すると、すべてがうまく機能f -a 123
します-a was triggered, Parameter: 123
。しかし、同じ行を2番目に実行すると、何も印刷されません。
この動作の原因は何ですか? Bash 3.2と4.3で発生しますが、Zsh 5.1ではうまく動作します。この例はZshではなくBashのものなので、これは驚くべきことです。
答え1
bashはオプションを取得します環境変数の使用選択トレース処理の最後のオプションパラメーター。実際には、OPTIND
同じシェルセッション内で呼び出されるたびに自動的にリセットされず、シェルが呼び出されたときgetopts
にのみリセットされます。したがって、getopts
同じパラメータを使用して同じセッションで2回目に呼び出すと、何も変更されず、OPTIND
操作がgetopts
完了したと考え、何もしません。
OPTIND
正しく動作するように手動でリセットできます。
$ OPTIND=1
$ f -a 123
-a was triggered, Parameter: 123
あるいは、関数をスクリプトに入れてスクリプトを複数回呼び出すだけです。
zshはオプションを取得します少し違う。OPTIND
通常、シェル関数が終了するたびに1にリセットされます。
答え2
どの関数でもローカル変数を宣言するのは神聖な習慣です。 $opt、$OPTARG、および $OPTIND を宣言すると、関数を呼び出すたびに getopts が実行されます。関数が完了すると、ローカル変数は削除されます。
#!/bin/bash
function some_func {
declare opt
declare OPTARG
declare OPTIND
while getopts ":a:" opt; do
echo $opt is $OPTARG
done
}
答え3
OPTIND=1
関数の先頭に設定する必要がありますf
。デフォルトでは1ですが、引数が解析されるにつれて増加します。もう一度呼び出すと、getopts
中断された部分から続きます。 2番目の電話が次の場合:
f -a 123 -a 999
999を印刷するとき。
答え4
呼び出されると、getopt
変数によって処理されたオプションを追跡しますOPTIND
。
以下を試してください。
#!/bin/bash
f () {
printf "Intro OPTIND: %d\n" "$OPTIND"
while getopts ":a:b:" opt; do
printf "Current OPTIND: %d\n" "$OPTIND"
case $opt in
a)
echo "-a was triggered, Parameter: $OPTARG" >&2
;;
b)
echo "-b was triggered, Parameter: $OPTARG" >&2
;;
esac
done
printf "Exit OPTIND: %d\n" "$OPTIND"
}
echo "Run #1"
f "$@"
echo "Run #2"
f "$@"
生産する:
./test -a foo -b bar
Run #1
Intro OPTIND: 1
Current OPTIND: 3
-a was triggered, Parameter: foo
Current OPTIND: 5
-b was triggered, Parameter: bar
Exit OPTIND: 5
Run #2
Intro OPTIND: 5
Exit OPTIND: 5
だからあなたはこれを行うことができます:
OPTIND=1
関数の先頭に。または一般的に、状況に応じてより良い方法は次のとおりです。
local OPTIND
使用しない場合、OPTIND
関数の実装中にwhileループは永久に続行されます。また、これを使用してパラメータ処理を再開できます。エラーが発生した後、またはxまたはyが別の関数を呼び出すと、中断された部分から再開されます。