さまざまなオプションを許可するシェルスクリプトがあり、一部はパラメータがあり、一部はパラメータがなく、一部は短く、一部は長いです。これらのオプションの一部を自分で処理し、残りの部分を管理する方法がわからない他のプログラムに渡す必要があります。getopts
不明なパラメータを保存するのと似たようなことがありますか?
program
たとえば、私のスクリプトが呼び出され、引数を受け入れる必要があるとします。
-n
1つのパラメータとして、--verbose
議論の余地がなく、-s
議論の余地はありません。
すべてのオプションとその引数を解析して印刷し、残りのecho rest:
項目を呼び出します。次の出力を観察する必要があります。
> program -sin42 --long --verbose
-s
-n with argument 42
--verbose
rest: -i --long
> program -n --short
-n with argument --short
> program -n
error: -n without argument
シェルスクリプトでこのようなことを行うことはできますか?
答え1
シェルで広く使用されていることはもちろん、これを行う標準的な方法もないと思います(つまり、最初から実装することが不足しています)。
非常に強力な組み込み機能をksh
サポートしていますが。getopts
これ(およびやや要求の厳しい要件)に基づいて、ksh
次のコードスニペットを使用して可能な基本的なソリューションの概要を説明しました。
while getopts ":[-][[n]:][99:verbose][s]" opt
do case $opt in
(n) n_arg=$OPTARG ;;
(99) verbose=1 ;;
(s) s=1 ;;
(*) arg_rest+=( "${@:OPTIND-1:1}" ) ;;
esac
done
shift OPTIND-1
printf "main opt(%s)=%s\n" "-n" "$n_arg"
printf "main opt(%s)=%s\n" "--verbose" "$verbose"
printf "main opt(%s)=%s\n" "-s" "$s"
function delegate
{
while getopts ":[-][i][98:long]" opt
do case $opt in
(i) int=1 ;;
(98) long=1 ;;
esac
done
shift OPTIND-1
printf "func opt(%s)=%s\n" "-i" "$int"
printf "func opt(%s)=%s\n" "--long" "$long"
}
printf "Delegate: '%s'\n" "${arg_rest[@]}"
delegate "${arg_rest[@]}"
プログラムは最初にすべてのオプションを解析し、必要に応じて内部変数を設定してから、不明なオプションを配列に保存します。これによりprintf
、設定を制御するためのいくつかのオプションが表示されます。その後、残りのオプションが委任される関数定義が提供され、その関数はコマンドに置き換えることもできます。最後に、残りのパラメータを使用して関数(または他のコマンド)を呼び出します。
ksh
(関数の説明はセッションgetopts
で呼び出されます。)ksh
getopts --man
このプログラムを実行すると、次のような出力が生成されます。
$ ksh ./getopts_script -s -n 23 --verbose -i --long
main opt(-n)=23
main opt(--verbose)=1
main opt(-s)=1
Delegate: '-i'
Delegate: '--long'
func opt(-i)=1
func opt(--long)=1
長いオプションをサポートするgetopts関数のシェル実装については、以下を参照してください。https://github.com/stephane-chazelas/misc-scripts/blob/master/getopts_long.sh
答え2
getopt
既知のオプションを予約注文するのは簡単です。残念ながら、不明なすべてのパラメータを拒否し、解析をすぐに停止します。
ただし、長いオプションがあまりにも複雑でない限り、bashをだましてgetopts
この操作を実行できます。いくつかのインスピレーションは以下から来ています。mkaurball
。ソースの下に注意事項が含まれています。
#!/bin/bash
while [ $OPTIND -le $# ]
do
if getopts ":sn:-:" argument
then
case $argument in
s) echo "-$argument" ;;
n) echo "-$argument with argument $OPTARG" ;;
\?) pass+=("-$OPTARG") ;;
-) lastarg=$((OPTIND - 1))
case "${!lastarg}" in
--verbose) echo "--verbose" ;;
--*) pass+=("--$OPTARG") ;;
*) echo "invalid argument: -"
exit 1 ;;
esac ;;
:) echo "$OPTARG without argument"
exit 1 ;;
esac
else
pass+=("${!OPTIND}")
let OPTIND++
fi
done
echo pass: "${pass[@]}"
- 通常、
getopts
sは条件として使用されませんwhile
。これにより、位置引数(つまり、オプションでも引数でもない引数)に遭遇するとすぐにループが停止します。代わりに、これらのケースはパラメータが収集される配列に追加されますpass
。 - パラメータ仕様には、長いオプションをパラメータ付きの短いオプションとして扱うことが
:-
含まれます。短いオプションの複合語の中間にダッシュを混在させると、不注意に使用するとこの問題が発生する可能性があるため、実際の引数が実際に2つのダッシュで始まることを確認することをお勧めします。したがって、ラップされたプログラムがオプションをオプションとして処理しようとすると、このメソッドは失敗します。getopts
--long
-
-long
-s-n
-short-with-dashes
- 本質的に
getopts
二重ダッシュも飲み込まれます。これは望ましいかもしれませんが、[ "${!OPTIND}" != '--' ] &&
前に挿入して避けることもできます。getopts
- ラッパーは入れ子になったパラメータ内にある必要があるため、長いパラメータを解析するのに少し難しいことがあります
case
。