現在、私は次の要件を持つBashスクリプトを書いています。
移植性の観点からはgetopts
が推奨される方法であることは知っていますが、AFAIKでは長いオプションをサポートしていません。
getopt
は長いオプションをサポートしていますが、 BashGuide はこれを強くお勧めします。
Getopt(1)を使用しないでください。 getoptは、空の引数文字列、または空白が埋め込まれた引数を処理できません。それが存在したことを忘れてください。
そのため、手動による解析のオプションがまだあります。これはエラーが発生しやすく、かなりのボイラープレートコードを生成します。自分でエラーを処理する必要があります(getopt(s)
は自分でエラー処理を行うと思います)。
それで、この場合、何が好ましい選択でしょうか?
さまざまなUnicesに移植できる必要がある場合は、POSIX shを使用する必要があります。そしてAFAIUでは、手作業で引数を処理する以外に選択肢はありません。
getopt
対getopts
は宗教的な問題のようです。 Bash FAQ のgetopt
に対する引数について:
「getopt
は空の引数文字列を処理できません」は、optional引数の既知の問題を参照しているようです。これはgetopts
がサポートしていないようですまったく(少なくともBash 4.2.24のhelp getopts
を読んでから)。 man getopt
から:
getopt(3)は、オプションの引数が空のオプションの引数を持つ長いオプションを解析できます(ただし、短いオプションの場合はこれを実行できません)。このgetopt(1)は、空のオプションの引数を存在しないかのように扱います。
「getopt
が埋め込み空白を含む[...]引数を処理できない」がどこから来るのかはわかりませんが、テストしてみましょう。
test.sh:
#!/usr/bin/env bash
set -o errexit -o noclobber -o nounset -o pipefail
params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")"
eval set -- "$params"
while true
do
case "$1" in
-a|--alpha)
echo alpha
shift
;;
-b|--bravo)
echo "bravo=$2"
shift 2
;;
-c|--charlie)
echo charlie
shift
;;
--)
shift
break
;;
*)
echo "Not implemented: $1" >&2
exit 1
;;
esac
done
実行:
$ ./test.sh -
$ ./test.sh -acb ' whitespace FTW '
alpha
charlie
bravo= whitespace FTW
$ ./test.sh -ab '' -c
alpha
bravo=
charlie
$ ./test.sh --alpha --bravo ' whitespace FTW ' --charlie
alpha
bravo= whitespace FTW
charlie
チェックして、私に合うように見えますが、誰かが私が文を完全に誤解した方法を誰かが示すと確信しています。もちろん、移植性の問題はまだ残っています。 Bashが古い、または利用できないプラットフォームに投資する価値がある時間を決定する必要があります。私自身のヒントは [〜#〜] yagni [〜#〜] および [〜#〜] kiss [〜#〜] ガイドラインを使用することです-それらのためにのみ開発してくださいあなたが知っている特定のプラットフォームが使用される予定です。開発時間が無限大になると、シェルコードの移植性は一般に100%になります。
これは getopts_long であり、スクリプト内に埋め込むことができるPOSIXシェル関数として記述されています。
Linux getopt
(from util-linux
)は、traditionalモードでない場合に正しく機能し、長いオプションをサポートしますが、他のUnicesに移植可能にする必要がある場合は、おそらく選択肢にはなりません。
最近のバージョンのksh93(getopts
)およびzsh(zparseopts
)には、ほとんどのUnicesで使用できるため、オプションである可能性のある長いオプションの解析のサポートが組み込まれています(ただし、インストールされていないことがよくあります)デフォルトで)。
もう1つのオプションは、Perl
とそのGetopt::Long
モジュールを使用することです。どちらも今日のほとんどのUnicesでPerl
にスクリプト全体を記述するか、Perlを呼び出してオプションを解析し、抽出した情報をシェルにフィードします。何かのようなもの:
parsed_ops=$(
Perl -MGetopt::Long -le '
@options = (
"foo=s", "bar", "neg!"
);
Getopt::Long::Configure "bundling";
$q="'\''";
GetOptions(@options) or exit 1;
for (map /(\w+)/, @options) {
eval "\$o=\$opt_$_";
$o =~ s/$q/$q\\$q$q/g;
print "opt_$_=$q$o$q"
}' -- "$@"
) || exit
eval "$parsed_ops"
# and then use $opt_foo, $opt_bar...
何ができるか、および他のオプションパーサーとどのように異なるかについては、perldoc Getopt::Long
を参照してください。
この問題に関するすべての議論は、解析コードを手動で作成するオプションを強調しています-そうしないと、機能と移植性について確信することができません。使いやすいオープンソースのコードジェネレーターで生成および再生成できるコードを記述しないことをお勧めします。 Argbash を使用します。これは、問題に対する明確な答えを提供するように設計されています。 十分に文書化されたコマンドラインアプリケーション 、 online または Docker image として利用可能なコードジェネレーター。
私はbashライブラリを使用しないことをお勧めします。一部のライブラリはgetopt
を使用しており(これにより移植性が大幅に低下します)、スクリプトに巨大な読み取り不可能なShell blobをバンドルするのは面倒です。
それをサポートするシステムではgetopt
を使用でき、サポートしないシステムではフォールバックを使用できます。
例えば - pure-getopt
は、純粋なBashで実装され、GNU getopt
。