シェルスクリプトでスイッチを処理するにはどうすればよいですか?


17

引数ではなく、スイッチとして認識-x--xxxx、スイッチとして機能する組み込みツールがありますか、それともすべての入力変数を調べ、ダッシュをテストし、その後引数を解析する必要がありますか?

回答:


16

を使用しgetoptsます。

POSIX仕様にあるように、かなり移植性があります。残念ながら、長いオプションはサポートしていません。

bash-hackers wikiの好意によるこのgetopts チュートリアルと、stackoverflowからのこの質問も参照してください。

短いオプションのみが必要な場合、getopts(非サイレントエラーレポートを使用する)の一般的な使用パターンは次のとおりです。

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done

3
その言及されるべきであるgetoptあなたがそれを使用する前に、必ずGNUのgetoptのように確認する必要がありますが、あなたにとにかくそれを使うべきではありませんgetopts、とにかくよりポータブル(と一般的によりよい)です。あなたがいる場合行う何らかの理由でそれを呼び出す必要性を、GNU固有の方法でそれを呼び出し、それが確実GETOPT_COMPATIBLEな環境ではありません。
クリスダウン

コロンは何をしてwhile getopts "ab:" optいますか?
ユーザー394

1
@ user394 :オプション文字の後は、引数が必要であることを示します。:最初の文字としてのA は、エラーメッセージを抑制することを意味します。
jw013

22

私はあなたがbashなどを使用していると思います。例:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"

1
+=配列で使用する場合は+1 。それができるとは知らなかった。いいね!
ジェームズ・スニーリンガー

5

パラメータを解析するサイクルを記述する必要があります。実際、getoptsコマンドを使用して簡単に実行できます。

これは、getoptsマニュアルページの簡単な例です。

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

2

汎用性があり、複数の種類のスイッチを任意の順序で使用できるようにするためのスクリプトを最近作成しました。明らかな法的理由のために完全なスクリプトを開示することはできません(現時点では私が持っていないことは言うまでもありませんが)、ここにその要点があります。あなたのスクリプトの:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

bashスクリプトを400行/ 15k文字未満に制限することをお勧めします。前述のスクリプトはこのサイズを超えて成長し、作業が非常に困難になりました。私はそれをPerlで書き直し始めました。これはタスクにより適しています。bashでスクリプトを作成するときは、このことに留意してください。Bashは小さなスクリプトやonelinersには最適ですが、もっと複雑なものはすべてPerlで記述するほうがよいでしょう。

注意してください、私は上記をテストしていないので、おそらく動作しませんが、あなたはそれから一般的なアイデアを得ます。


options最後に呼び出す方法は正しくありません-bash: syntax error near unexpected token $@。として呼び出しoptions "$@"ます。
クリスダウン

うん、PerlとBashを混ぜた。修正しました。
レブシェード

それ while(($#))代わりに条件はありませんか?
マナトワーク

なぜ2組の括弧が必要なのですか $#ですか?編集:そのとおりです。修正済みwhile (( "$#" ))
laebshade
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.