あるスクリプトから別のスクリプトにすべてのパラメータを渡そうとします。ただし、別のスクリプトをインポートすると問題が発生します。すべてのパラメータが正しく渡されません。
最初の.sh:
#!/usr/bin/bash
while getopts a option
do
case "${option}"
in
a) echo 'OptionA:somevalue';;
esac
done
# This way works
./second.sh "$@"
# Does not work when source command is used
#source ./second.sh "$@"
2番目の.sh:
#!/usr/bin/bash
while getopts b:c option
do
case "${option}"
in
b) echo 'OptionB:'"${OPTARG}";;
c) echo 'OptionC:somevalue';;
esac
done
出力:
$ ./test.sh -a -b foo -c
OptionA:somevalue
./first.sh: illegal option -- b
./second.sh: illegal option -- a
OptionB:foo
OptionC:somevalue
予想出力:
$ ./test.sh -a -b foo -c
OptionA:somevalue
OptionB:foo
OptionC:somevalue
達成する目標は何ですか?
second.sh
パラメータを正しく渡し、削除し、他のシェルと互換性がillegal option
あるようにするには、sourceコマンドを使用します。
編集:より明確な例は、質問を再更新しました。
答え1
while getopts
一般的な状況でループがどのように機能するかを検討してください。getopts
コマンドライン引数自体(位置引数)を変更しなくても、ループが繰り返されるたびに呼び出され、次に見つかる引数リストの場所を知る必要があります。呼び出しから明示的に渡されない「隠された」状態を維持してこれを行う必要があります。
これはバッシュリファレンスマニュアル:
呼び出すたびに、
getopts
次のオプションをシェル変数に入れます。名前、初期化名前存在しない場合は、変数として処理される次のパラメータのインデックスですOPTIND
。OPTIND
シェルまたはシェルスクリプトが呼び出されるたびに1に初期化されます。オプションに引数が必要な場合、getoptsは引数を変数に入れますOPTARG
。シェルはOPTIND
自動的にリセットされません。getopts
新しいパラメータセットを使用するには、同じシェル呼び出し内の呼び出し間で手動でリセットする必要があります。
スクリプトを取得したらOPTIND
。
マニュアルに示すように、OPTIND=1
新しいgetopts
サイクルを開始する前に設定するだけです。 (設定を解除しないでください。これにより、一部のシェルに問題が発生する可能性があります。)
たとえば、
set -- -a foo
while getopts a:b: option; do
echo "$option: $OPTARG"
done
set -- -b first -b second
# OPTIND=1
while getopts a:b: option; do
echo "$option: $OPTARG"
done
印刷
a: foo
b: second
2番目のループは最初のループの終わりに続くので-b first
。
OPTIND=1
中間割り当てのコメントを外すと、予想される出力が得られます。
a: foo
b: first
b: second
パラメータを別々に保存すると、単一の文字列が構成されますが$@
、args+="-a ${OPTARG} "
コマンドラインパラメータセットは実際にはさまざまな文字列のリスト/配列です。パラメータ自体にスペースが含まれている場合、違いは最も顕著です。 2つの引数セット(-a
、、foo bar
)、(-a foo
、bar
)が連結されており、-a foo bar
後者の文字列は区別できません。
代わりに、配列を使用してパラメータを一意の文字列として保存します。
while getopts a:b:d option
do
case "${option}"
in
a) args+=(-a "$OPTARG");;
b) args+=(-b "$OPTARG");;
d) echo 'Option:D';;
esac
done
# ...
./args.sh "${args[@]}"
(望むより 変数に保存されたコマンドをどのように実行できますか?より多くの例を見るには、など)
気づく、標準.
(ドット)コマンドソーススクリプトはパラメータを使用しませんが、ソーススクリプトは$@
デフォルトスクリプトと同じです。 (ソーススクリプトで変更された内容は$@
デフォルトスクリプトに表示されます。)
Bash .
/はsource
新しい引数セット渡しをサポートしていますが、source filename
引数セットなしで呼び出すと、ソーススクリプトはいいえ空のリストを取得しますが、基本スクリプトのパラメータが含まれています。
その場合は、次のようにしてください。
source ./args.sh "${args[@]}"
空でないことを確認することをお勧めしますargs
。または、別のスクリプトをインポートする前に、基本スクリプトのパラメータをリセットしてください。もちろん、これにより元のパラメータセットが破壊されますが、必要に応じて他の配列に保存することもできます。
orig_args=( "$@" ) # if needed
set -- "${args[@]}"
source ./args.sh