getopt、getopts、または手動解析-短いオプションと長いオプションの両方をサポートする場合に使用するもの


32

現在、次の要件を持つBashスクリプトを作成しています。

  • さまざまなUnix / Linuxプラットフォームで実行する必要があります
  • 短いオプションと(GNU)長いオプションの両方をサポートする必要があります

私はそれgetoptsが移植性の観点から好ましい方法になることを知っていますが、知る限りでは長いオプションをサポートしていません。

getopt長いオプションをサポートしますが、BashGuideはそれに対して強く推奨します:

getopt(1)を使用しないでください。getoptは、空の引数文字列、または空白が埋め込まれた引数を処理できません。それが存在したことを忘れてください。

そのため、手動解析のオプションがまだあります。これはエラーが発生しやすく、かなりの定型コードを生成するため、自分でエラーを処理する必要がありgetopt(s)ます(自分でエラー処理を行うと思います)。

それで、この場合の好ましい選択は何でしょうか?


回答:


9

さまざまなUnicesに移植可能にする必要がある場合は、POSIX shに固執する必要があります。AFAIUでは、手でローリング引数を処理する以外に選択肢はありません。


25

getoptvs getoptsは宗教的な問題のようです。引数のようgetoptバッシュよくある質問

  • getopt空の引数文字列を処理できません」は、オプションの引数に関する既知の問題を指しているようですgetopts(少なくともhelp getoptsBash 4.2.24の読み取りから)。から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が古いプラットフォームまたはないプラットフォームに投資する価値がある時間を決定する必要があります。私自身のヒントは、YAGNIKISSのガイドラインを使用することです-使用されることがわかっている特定のプラットフォーム用にのみ開発してください。シェルコードの移植性は通常、開発時間が無限に近づくにつれて100%になります。


11
OPは、多くのUnixプラットフォームに移植できる必要があると述べましたが、getoptここで引用しているのはLinux固有のものです。getoptはの一部ではないことに注意してください。これはbashGNUユーティリティではなく、Linuxではutil-linuxパッケージに同梱されています。
ステファンシャゼル

2
ほとんどのプラットフォームにはがありgetopt、長いオプションまたは引数の空白をサポートするものがLinux AFAIKにのみ付属しています。他のものはSystem V構文のみをサポートします。
ステファンシャゼル

7
getoptLinuxがリリースされるずっと前にSystem Vから来た伝統的なコマンドです。getopt標準化されたことはありません。POSIX、Unix、Linux(LSB)のいずれもgetoptコマンドを標準化したことはありません。getopts3つすべてで指定されていますが、長いオプションはサポートされていません。
ステファンシャゼル

1
この議論に加えて、これは伝統的なものではありませんgetopt。@StéphaneChazelasで示されるlinux-utilsフレーバーです。上記の構文を無効にするレガシーオプションがあります。特に、マンページには「GETOPT_COMPATIBLEがgetoptにSYNOPSISで指定された最初の呼び出し形式を強制的に使用する」と記載されています。ただし、ターゲットシステムにこのパッケージがインストールされていることが予想される場合は、これが完全に進むべき方法です。元のgetoptはひどく、Bashのgetoptは非常に制限されているためです
-n.caillou

1
「getoptの従来のバージョンは、空の引数文字列、または空白が埋め込まれた引数を処理できない」と主張するOPのリンク。また、getoptのutil-linuxバージョンを使用しないでください。証拠がなく、正確ではありません。簡単な調査(5年以上後)では、ArchLinux、SUSE、Ubuntu、RedHat、Fedora、CentOS(およびほとんどの派生バリアント)で利用可能なgetoptのデフォルトバージョンはすべて、オプションの引数と空白付きの引数をサポートしています。
mtalexan

10

このgetopts_longはPOSIXシェル関数として記述されており、スクリプト内に埋め込むことができます。

Linux getopt(from util-linux)は、従来のモードではない場合に正しく機能し、長いオプションをサポートしますが、他のUnicesに移植する必要がある場合はおそらくオプションではないことに注意してください。

最近のバージョンのksh93(getopts)およびzsh(zparseopts)には、ほとんどのUnicesで利用可能なオプションである可能性のある長いオプションの解析の組み込みサポートがあります(多くの場合、デフォルトではインストールされません)。

別のオプションは、スクリプト全体を記述するか、単にオプションを解析して抽出した情報をシェルに供給するために単にperlを呼び出すことにより、現在ほとんどのUnicesで使用可能なモジュールperlとそのGetopt::Longモジュールを使用すること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それが何ができるかのために、それは他のオプションのパーサとどのように異なりますか。


2

この問題に関するすべての議論は、解析コードを手動で記述するオプションを強調しています-その場合にのみ、機能と移植性を確認できます。使いやすいオープンソースのコードジェネレーターで生成および再生成できるコードを記述しないことをお勧めします。Argbashを使用します。これは、問題に対する明確な答えを提供するように設計されています。これは、コマンドラインアプリケーションオンライン、またはDockerイメージとして利用できる、十分に文書化されたコードジェネレーターです。

bashライブラリを使用することをお勧めします。一部のライブラリはgetopt(非常に移植性が低くなります)使用しており、スクリプトに巨大な読み取り不能シェルブロブをバンドルするのは苦痛です。


0

getoptそれをサポートするシステムで使用し、サポートしないシステムでフォールバックを使用できます。

たとえば pure-getopt、純粋なBashで実装され、GNUのドロップイン代替品ですgetopt

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.