0

-cそれぞれにオプションが必要なスクリプトを作成したいと思い-fます。

以下のスクリプトを実行すると、予期しないエラーが発生します。

$ ./user.sh -c
./user.sh: option requires an argument -- c

Usage: user.sh -c username -f filename
   -c username
   -f SSH public key

$ ./user.sh -c gg
Error: You have not given a filename.

最初のケースでは、 のオプションが欠落していると言われたらよかったのですが-c、2 番目のケースでは、欠落していると言われればよかったと思います-f

質問

このようなエラー処理を行うにはどうすればよいですか? また、何が間違っているのでしょうか?

user.sh

#!/bin/bash                                                                                             

usage () {
    echo "Usage: user.sh -c username -f filename"
    echo "   -c username"
    echo "   -f SSH public key"
    echo ""
}

if ! [ "$*"  ]; then
    usage
    exit 1
fi

while getopts "c:f:" opt; do
    case $opt in
        c) user=$OPTARG;;
        f) filename=$OPTARG;;
        \?)
            echo
            usage
            exit 1;;
        *) echo "Internal error: Unknown option.";;
    esac
done

if ! [ $filename ]; then
    echo "Error: You have not given a filename."
    exit 1
fi

if ! [ $user ]; then
    echo "Error: You have not given an username."
    exit 1
fi
4

1 に答える 1

3

「オプションの後にはユーザー名が必要ですc:」と書かれています。-c

エラーメッセージには、「-cオプションの後にユーザー名がありませんでした」と表示されます。

確かに、「ユーザー名」については触れていませんが、それはオプションの後に続くものが何であるかがわからないため-cです。

getoptsビルトインは必須オプションを処理できません。必須オプションが実際に渡されたことを確認して、自分でコーディングする必要があります。同じオプションが 2 回指定されても問題ありません。それが重要な場合、コードはそれに対処する必要があります。(最後に指定した値を有効にするのは簡単です。)

現代的なスタイルは、必須の引数の前にオプション文字を避けることです。私はこの変更に全面的に賛成しているわけではありません。これは、引数の順序付けが重要になることを意味します。これは、オプション文字を使用して後続の内容を示す場合とは異なります。オプション文字がなければ、次のように記述します:./user.sh username filenameが、オプション文字を使用すると、次のいずれかを記述して動作を期待できます。

./user.sh -c username -f filename
./user.sh -f filename -c username

余分な引数についても心配する責任があることに注意してください。通常は次のものを使用します。

shift $(($OPTIND - 1))

処理された引数を削除すると、次のことができます。

case "$#" in
(0) : No extra arguments - OK;;
(*) echo "$0: Too many arguments" >&2; exit 1;;
esac

そして、そのテーマのバリエーション。エラー レポートは標準出力ではなく標準エラーに送信されることに注意してください。>&2リダイレクトでは、代わりに標準出力 (ファイル記述子 1) が標準エラー (ファイル記述子 2) に送信されます。

あいまいさを避けるために、使用関数を少し異なる方法でコーディングします。

usage()
{
    {
    echo "Usage: user.sh -c username -f filename"
    echo "   -c username    Name of user to connect as"
    echo "   -f filename    SSH public key file"
    echo ""
    } >&2
}

内側のブレースは、サブシェルを起動せずに I/O リダイレクトをまとめて実行します。これは、多数の echo コマンドを同じ場所に送信する必要がある場合に役立ちます。また、詳細情報を少し違った方法で提示したので、ユーザーは「SSH 公開鍵」が-f. 純粋なオプション フラグがある場合は、その後に空白が続きます。

    echo "   -V             Print version information and exit"
于 2012-10-31T20:06:07.850 に答える