getoptsを使用してすべてのパラメータを別のソースbashスクリプトに渡す

getoptsを使用してすべてのパラメータを別のソースbashスクリプトに渡す

あるスクリプトから別のスクリプトにすべてのパラメータを渡そうとします。ただし、別のスクリプトをインポートすると問題が発生します。すべてのパラメータが正しく渡されません。

最初の.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次のオプションをシェル変数に入れます。名前、初期化名前存在しない場合は、変数として処理される次のパラメータのインデックスですOPTINDOPTINDシェルまたはシェルスクリプトが呼び出されるたびに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 foobar)が連結されており、-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

おすすめ記事