Case ステートメントのインライン グループ化コマンドが機能しません: 予期しないマーカー ";;"近くに構文エラーがあります。

Case ステートメントのインライン グループ化コマンドが機能しません: 予期しないマーカー ";;"近くに構文エラーがあります。

私のbashスクリプトからパラメータを解析します。特定のパターンなしで「path」という1つのパラメータのみを許可しようとしています。大文字と小文字が一致しない他のパラメーターはスクリプトを終了させます。例は次のとおりです。

#!/bin/bash
while [ "$#" -gt 0 ]; do
    case "$1" in
        -v|--verbose) verbose=1 ;;
        -h|--help)
            echo "Usage: $(basename "$0") [OPTIONS] [PATH]"
            echo "Does something interesting with the given path."
            echo ""
            echo "OPTIONS"
            echo "  -v,   --verbose                 Prints verbose information."
            echo "  -h,   --help                    Prints this help message."
            exit 0
            ;;
        *) { test -z $path && path=$1 } || { echo "Invalid command line flag $1" >&2 && exit 1 } ;;
    esac
    shift
done

ただし、この行は{ test -z $path && path=$1 } || { echo "Invalid command line flag $1" >&2 && exit 1 } ;;次の場合に失敗します。

myscript: line 14 syntax error near unexpected token `;;'
myscript: line 14: `           *) { test -z $path && path=$1 } || { echo "Invalid command line flag $1" >&2 && exit 1 } ;;'

単にif-elseステートメントを書くことができることを知っていますが、インラインでグループ化できないのはなぜですか?中かっこを削除するとexit 1常に到達します。

答え1

1行のコマンドグループ内のコマンドのリストはセミコロンで終わる必要があります。{ list; }そうでなければ{ list }

例えば、

$ bash -c 'case $1 in *) { echo foo && echo bar } ;; esac' bash baz
bash: -c: line 0: syntax error near unexpected token `;;'
bash: -c: line 0: `case $1 in *) { echo foo && echo bar } ;; esac'

失敗する、

$ bash -c 'case $1 in *) { echo foo && echo bar; } ;; esac' bash baz
foo
bar

効果がありました。

バラよりコマンドリストと}の間の区切り記号そしてbashマニュアルセクションコマンドのグループ化

答え2

以前の回答とコメントは、主なエラーの原因をカバーしています。

私は複数行使用メッセージをスクリプトの別の部分(サブルーチンなど)に移動し、セクションで-h|-help)単にサブルーチンを呼び出すように提案を投稿しました。

USAGE () {
  echo "This is the first line of my usage message"
  echo "This is another line"
  echo "Etc."
}

(farther down the script)

case "$1" in
    -v|--verbose) verbose=1 ;;
       -h|--help) USAGE ; exit 0 ;;
               *) # your code here ;;
esac

または、ここでドキュメントを使用して複数行の使用法メッセージを文字列変数に組み合わせてから、Caseステートメント句を使用してその変数を表示して終了することもできます。

# fill $USAGE with a here document that isn't indented
USAGE=$(cat - <<EOUSAGE
Usage: $(basename "$0") [OPTIONS] [PATH]
Does something interesting with the given path.

OPTIONS
  -v,   --verbose                 Prints verbose information.
  -h,   --help                    Prints this help message.
EOUSAGE
)  # USAGE=$( ... ) ends here

(farther down the script)

case "$1" in
  -v|--verbose) verbose=1 ;;
     -h|--help) echo "$USAGE" ; exit 0 ;;
             *) # your code here ;;
esac

複数行のメッセージを書くことは複数のechoコマンドを書くよりもはるかに混乱しにくく、テキストの空白行や引用符が問題にならないので、ここでは文書化方法を使用することを好みます。また、インデントされていないため、ターミナルウィンドウで各行がどれだけ離れているかを確認でき、より長い行は読みやすくするために改行できます。

関連情報