getoptsを使用してLinuxシェルスクリプトオプションを解析する方法
公開: 2022-06-25
Linuxシェルスクリプトがコマンドラインオプションと引数をより適切に処理することを望みますか? Bash getoptsビルトインを使用すると、コマンドラインオプションをフィネスで解析できます。これも簡単です。 その方法をお見せします。
getoptsビルトインの紹介
Bashスクリプトに値を渡すことは、非常に簡単なことです。 コマンドラインまたは別のスクリプトからスクリプトを呼び出し、スクリプト名の後ろに値のリストを指定します。 これらの値は、スクリプト内で変数としてアクセスできます。最初の変数は$2 $1の変数は$2というように始まります。
ただし、オプションをスクリプトに渡したい場合、状況はすぐに複雑になります。 オプションとは、 lsなどのプログラムが処理できるオプション、フラグ、またはスイッチを意味します。 それらの前にはダッシュ「 - 」が付いており、通常、プログラムの機能の一部をオンまたはオフにするためのインジケーターとして機能します。
lsコマンドには、主に出力のフォーマットに関連する50を超えるオプションがあります。 -X (拡張子で並べ替え)オプションは、ファイル拡張子のアルファベット順に出力を並べ替えます。 -U (ソートされていない)オプションは、ディレクトリー順にリストされます。
オプションはそれだけです—それらはオプションです。 ユーザーがどのオプションを使用するかを選択するかどうかはわかりません。また、コマンドラインにそれらをリストする順序もわかりません。 これにより、オプションの解析に必要なコードが複雑になります。
一部のオプションがオプション引数と呼ばれる引数を取る場合、事態はさらに複雑になります。たとえば、 ls -w (width)オプションの後には、出力の最大表示幅を表す数値が続くことを想定しています。 そしてもちろん、単なるデータ値であり、オプションではない他のパラメーターをスクリプトに渡す場合もあります。
ありがたいことに、 getoptsはこの複雑さを処理します。 また、組み込みであるため、Bashシェルを備えたすべてのシステムで使用できるため、インストールする必要はありません。
注:getoptsはgetoptではありません
getoptと呼ばれる古いユーティリティがあります。 これは小さなユーティリティプログラムであり、組み込みではありません。 動作が異なるgetoptにはさまざまなバージョンがありますが、組み込みのgetopsはPOSIXガイドラインに従います。
getoptsと入力します
getoptと入力します

getoptは組み込みではないため、空白を適切に処理するなど、 getoptsが行う自動の利点の一部を共有していません。 getoptsを使用すると、Bashシェルがスクリプトを実行し、Bashシェルがオプションの解析を実行します。 解析を処理するために外部プログラムを呼び出す必要はありません。
トレードオフは、 getoptsが二重破線の長い形式のオプション名を処理しないことです。 したがって、 -wのようにフォーマットされたオプションを使用できますが、「 ---wide-format 」は使用できません。 一方、オプション-a 、 -b 、およびを受け入れるスクリプトがある場合、 -cgetoptsを使用すると、 -abc 、 -bca 、または-bacなどのようにそれらを組み合わせることができます。
この記事ではgetoptsについて説明およびデモンストレーションしているため、コマンド名に最後の「s」を追加してください。
関連: Windowsコマンドラインでファイルパスのスペースをエスケープする方法
簡単な要約:パラメーター値の処理
このスクリプトは、 -aや-bのような破線のオプションを使用しません。 コマンドラインで「通常の」パラメータを受け入れ、これらはスクリプト内で値としてアクセスされます。
#!/ bin / bash #変数を1つずつ取得する echo "Variable One:$ 1" echo "Variable Two:$ 2" echo "Variable Three:$ 3" #変数をループする 「 $@」のvarの場合 エコー"$ var" 終わり
パラメータは、変数$1 、 $2 、または$3としてスクリプト内でアクセスされます。
このテキストをエディタにコピーして、「variables.sh」というファイルとして保存します。 chmodコマンドで実行可能にする必要があります。 ここで説明するすべてのスクリプトに対して、この手順を実行する必要があります。 毎回、適切なスクリプトファイルの名前に置き換えてください。
chmod+x変数.sh

パラメータを指定せずにスクリプトを実行すると、この出力が得られます。
./variables.sh

パラメータを渡さなかったため、スクリプトにはレポートする値がありません。 今回はいくつかのパラメータを提供しましょう。
./variables.shオタクのやり方

予想どおり、変数$1 、 $2 、および$3がパラメーター値に設定されており、これらが出力されていることがわかります。
このタイプの1対1のパラメーター処理は、パラメーターがいくつあるかを事前に知る必要があることを意味します。 スクリプトの下部にあるループは、パラメーターの数を気にせず、常にすべてのパラメーターをループします。
4番目のパラメーターを指定すると、それは変数に割り当てられませんが、ループはそれを処理します。
./variables.shウェブサイトをオタクにする方法

2つの単語を引用符で囲むと、それらは1つのパラメーターとして扱われます。
./variables.sh「オタクにする」方法

オプション、引数付きのオプション、および「通常の」データ型パラメーターのすべての組み合わせを処理するスクリプトが必要な場合は、オプションを通常のパラメーターから分離する必要があります。 これは、引数の有無にかかわらず、すべてのオプションを通常のパラメーターの前に配置することで実現できます。
しかし、私たちが歩くことができる前に走らないようにしましょう。 コマンドラインオプションを処理するための最も単純なケースを見てみましょう。
取り扱いオプション
whileループでgetoptsを使用します。 ループの各反復は、スクリプトに渡された1つのオプションで機能します。 いずれの場合も、変数OPTIONはgetoptsで識別されるオプションに設定されます。
ループが繰り返されるたびに、 getoptsは次のオプションに進みます。 これ以上オプションがない場合、 getoptsはfalseを返し、 whileループは終了します。
OPTION変数は、各caseステートメント句のパターンと照合されます。 caseステートメントを使用しているため、コマンドラインでオプションが提供される順序は関係ありません。 各オプションはcaseステートメントにドロップされ、適切な句がトリガーされます。
caseステートメントの個々の句を使用すると、スクリプト内でオプション固有のアクションを簡単に実行できます。 通常、実際のスクリプトでは、各句に変数を設定します。これらはスクリプトのさらに先のフラグとして機能し、一部の機能を許可または拒否します。
このテキストをエディターにコピーし、「options.sh」というスクリプトとして保存して、実行可能にします。
#!/ bin / bash
getopts'abc'OPTION; 行う
ケース「$OPTION」
a)
echo"オプションa使用済み";;
b)
エコー「オプションb使用済み」
;;
c)
エコー「使用されたオプションc」
;;
?)
echo "使用法:$(basename $ 0)[-a] [-b] [-c]"
出口1
;;
esac
終わりこれは、whileループを定義する行です。

getopts'abc'OPTION; 行う
getoptsコマンドの後にオプション文字列が続きます。 これは、オプションとして使用する文字を一覧表示します。 このリストの文字のみをオプションとして使用できます。 したがって、この場合、 -dは無効になります。 getoptsは疑問符「 ? 」を返すため、これは?)句によってトラップされます。 未確認のオプションの場合は」。 その場合、正しい使用法がターミナルウィンドウに出力されます。
echo "使用法:$(basename $ 0)[-a] [-b] [-c]"
慣例により、このタイプの正しい使用法メッセージでオプションを角かっこ「 [] 」で囲むことは、オプションがオプションであることを意味します。 basenameコマンドは、ファイル名からすべてのディレクトリパスを削除します。 スクリプトファイル名は、Bashスクリプトでは$0に保持されます。
このスクリプトをさまざまなコマンドラインの組み合わせで使用してみましょう。
./options.sh -a
./options.sh -a -b -c
./options.sh -ab -c
./options.sh -cab

ご覧のとおり、オプションのすべてのテストの組み合わせが解析され、正しく処理されます。 存在しないオプションを試してみるとどうなりますか?
./options.sh -d

使用法句がトリガーされます。これは適切ですが、シェルからエラーメッセージも表示されます。 それはあなたのユースケースにとって重要かもしれないし、そうでないかもしれません。 エラーメッセージを解析する必要がある別のスクリプトからスクリプトを呼び出している場合、シェルがエラーメッセージも生成していると、さらに困難になります。
シェルエラーメッセージをオフにするのは非常に簡単です。 オプション文字列の最初の文字としてコロン「 : 」を入力するだけです。
「options.sh」ファイルを編集して、オプション文字列の最初の文字としてコロンを追加するか、このスクリプトを「options2.sh」として保存して実行可能にします。
#!/ bin / bash
getopts':abc' OPTION; 行う
ケース「$OPTION」
a)
エコー「使用済みオプション」
;;
b)
エコー「オプションb使用済み」
;;
c)
エコー「使用されたオプションc」
;;
?)
echo "使用法:$(basename $ 0)[-a] [-b] [-c]"
出口1
;;
esac
終わりこれを実行してエラーを生成すると、シェルメッセージなしで独自のエラーメッセージを受け取ります。
./options2.sh.sh -d

オプション引数でのgetoptsの使用
オプションの後に引数が続くことをgetoptsに伝えるには、オプション文字列のオプション文字のすぐ後ろにコロン「 : 」を付けます。
オプション文字列の「b」と「c」の後にコロンを付けると、 getoptはこれらのオプションの引数を期待します。 このスクリプトをエディターにコピーして「arguments.sh」として保存し、実行可能にします。
オプション文字列の最初のコロンは、シェルエラーメッセージを抑制するために使用されることを忘れないでください。これは、引数の処理とは関係ありません。
getoptが引数を持つオプションを処理するとき、引数はOPTARG変数に配置されます。 この値をスクリプトの他の場所で使用する場合は、別の変数にコピーする必要があります。
#!/ bin / bash
getopts':ab:c:' OPTION; 行う
ケース「$OPTION」
a)
エコー「使用済みオプション」
;;
b)
argB = "$ OPTARG"
echo "オプションbで使用:$ argB"
;;
c)
argC = "$ OPTARG"
echo "オプションcで使用:$ argC"
;;
?)
echo "使用法:$(ベース名$ 0)[-a][-b引数][-c引数]"
出口1
;;
esac
終わりそれを実行して、それがどのように機能するかを見てみましょう。
./arguments.sh -a -b "how to geek" -c reviewgeek
./arguments.sh -c reviewgeek -a

これで、コマンドラインで指定された順序に関係なく、引数の有無にかかわらずオプションを処理できるようになりました。
しかし、通常のパラメーターはどうですか? 先ほど、オプションの後にコマンドラインに配置する必要があることはわかっていました。 そうするとどうなるか見てみましょう。
混合オプションとパラメーター
以前のスクリプトを変更して、もう1行追加します。 whileループが終了し、すべてのオプションが処理されると、通常のパラメーターにアクセスしようとします。 値を$1で出力します。
このスクリプトを「arguments2.sh」として保存し、実行可能にします。
#!/ bin / bash
getopts':ab:c:' OPTION; 行う
ケース「$OPTION」
a)
エコー「使用済みオプション」
;;
b)
argB = "$ OPTARG"
echo "オプションbで使用:$ argB"
;;
c)
argC = "$ OPTARG"
echo "オプションcで使用:$ argC"
;;
?)
echo "使用法:$(ベース名$ 0)[-a][-b引数][-c引数]"
出口1
;;
esac
終わり
echo "変数は次のとおりです:$ 1"次に、オプションとパラメータのいくつかの組み合わせを試してみます。
./arguments2.sh dave
./arguments2.sh -a dave
./arguments2.sh -a -c how-to-geek dave

これで問題がわかります。 オプションが使用されるとすぐに、 $1以降の変数はオプションフラグとその引数で埋められます。 最後の例では、 $4はパラメーター値「dave」を保持しますが、使用されるオプションと引数の数がわからない場合、スクリプトでどのようにアクセスしますか?
答えは、 OPTINDとshiftコマンドを使用することです。
shiftコマンドは、タイプに関係なく、パラメーターリストから最初のパラメーターを破棄します。 他のパラメーターは「シャッフルダウン」するため、パラメーター2はパラメーター1になり、パラメーター3はパラメーター2になります。 したがって、 $2は$1になり、 $3は$2になります。
shiftに数値を指定すると、その数のパラメーターがリストから削除されます。
OPTINDは、オプションと引数が検出されて処理されるときにそれらをカウントします。 すべてのオプションと引数が処理されると、 OPTINDはオプションの数より1つ多くなります。 したがって、Shiftを使用してパラメーターリストからパラメーターをトリミング(OPTIND-1) 、 $1以降の通常のパラメーターが残ります。
それはまさにこのスクリプトが行うことです。 このスクリプトを「arguments3.sh」として保存し、実行可能にします。
#!/ bin / bash
getopts':ab:c:' OPTION; 行う
ケース「$OPTION」
a)
エコー「使用済みオプション」
;;
b)
argB = "$ OPTARG"
echo "オプションbで使用:$ argB"
;;
c)
argC = "$ OPTARG"
echo "オプションcで使用:$ argC"
;;
?)
echo "使用法:$(ベース名$ 0)[-a][-b引数][-c引数]"
出口1
;;
esac
終わり
echo "Before-変数1は:$ 1"
シフト"$(($ OPTIND -1))"
echo "After-変数1は:$ 1"
echo "残りの引数(オペランド)"
「$@」のxの場合
行う
エコー$x
終わりこれは、オプション、引数、およびパラメーターを組み合わせて実行します。
./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tich

shiftを呼び出す前は、 $1が「-a」を保持していましたが、シフトコマンドの後、 $1は、最初の非オプション、非引数パラメーターを保持していることがわかります。 オプションの解析を行わないスクリプトの場合と同じように、すべてのパラメーターを簡単にループできます。
オプションがあるのは常に良いことです
スクリプトでのオプションとその引数の処理は、複雑である必要はありません。 getoptsを使用すると、POSIX準拠のネイティブスクリプトとまったく同じように、コマンドラインオプション、引数、およびパラメーターを処理するスクリプトを作成できます。


