getoptsを使用してLinuxシェルスクリプトオプションを解析する方法

公開: 2022-06-25
ターミナルテキストを表示するノートパソコンの画面。
fatmawati achmad zaenuri / Shutterstock.com

Linuxシェルスクリプトがコマンドラインオプションと引数をより適切に処理することを望みますか? Bash getoptsビルトインを使用すると、コマンドラインオプションをフィネスで解析できます。これも簡単です。 その方法をお見せします。

getoptsビルトインの紹介

Bashスクリプトにを渡すことは、非常に簡単なことです。 コマンドラインまたは別のスクリプトからスクリプトを呼び出し、スクリプト名の後ろに値のリストを指定します。 これらの値は、スクリプト内で変数としてアクセスできます。最初の変数は$2 $1の変数は$2というように始まります。

ただし、オプションをスクリプトに渡したい場合、状況はすぐに複雑になります。 オプションとは、 lsなどのプログラムが処理できるオプション、フラグ、またはスイッチを意味します。 それらの前にはダッシュ「 - 」が付いており、通常、プログラムの機能の一部をオンまたはオフにするためのインジケーターとして機能します。

lsコマンドを使用してLinux上のファイルとディレクトリを一覧表示する方法
関連するlsコマンドを使用してLinux上のファイルとディレクトリを一覧表示する方法

lsコマンドには、主に出力のフォーマットに関連する50を超えるオプションがあります。 -X (拡張子で並べ替え)オプションは、ファイル拡張子のアルファベット順に出力を並べ替えます。 -U (ソートされていない)オプションは、ディレクトリー順にリストされます。

オプションはそれだけです—それらはオプションです。 ユーザーがどのオプションを使用するかを選択するかどうかはわかりません。また、コマンドラインにそれらをリストする順序もわかりません。 これにより、オプションの解析に必要なコードが複雑になります。

一部のオプションがオプション引数と呼ばれる引数を取る場合、事態はさらに複雑になります。たとえば、 ls -w (width)オプションの後には、出力の最大表示幅を表す数値が続くことを想定しています。 そしてもちろん、単なるデータ値であり、オプションではない他のパラメーターをスクリプトに渡す場合もあります。

ありがたいことに、 getoptsはこの複雑さを処理します。 また、組み込みであるため、Bashシェルを備えたすべてのシステムで使用できるため、インストールする必要はありません。

注:getoptsはgetoptではありません

getoptと呼ばれる古いユーティリティがあります。 これは小さなユーティリティプログラムであり、組み込みではありません。 動作が異なるgetoptにはさまざまなバージョンがありますが、組み込みのgetopsはPOSIXガイドラインに従います。

 getoptsと入力します
getoptと入力します

typeコマンドを使用して、getopとgetopsの違いを確認します

getoptは組み込みではないため、空白を適切に処理するなど、 getoptsが行う自動の利点の一部を共有していません。 getoptsを使用すると、Bashシェルがスクリプトを実行し、Bashシェルがオプションの解析を実行します。 解析を処理するために外部プログラムを呼び出す必要はありません。

トレードオフは、 getoptsが二重破線の長い形式のオプション名を処理しないことです。 したがって、 -wのようにフォーマットされたオプションを使用できますが、「 ---wide-format 」は使用できません。 一方、オプション-a-b 、および-cを受け入れるスクリプトがある場合、 getoptsを使用すると、 -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 

chmodコマンドを使用してスクリプトを実行可能にする

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

 ./variables.sh 

パラメータなしでスクリプトを実行する

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

 ./variables.shオタクのやり方

パラメータとして3つの単語を使用してスクリプトを実行する

予想どおり、変数$1$2 、および$3がパラメーター値に設定されており、これらが出力されていることがわかります。

このタイプの1対1のパラメーター処理は、パラメーターがいくつあるかを事前に知る必要があることを意味します。 スクリプトの下部にあるループは、パラメーターの数を気にせず、常にすべてのパラメーターをループします。

4番目のパラメーターを指定すると、それは変数に割り当てられませんが、ループはそれを処理します。

 ./variables.shウェブサイトをオタクにする方法

3つしか処理できないスクリプトに4つのパラメーターを渡す

2つの単語を引用符で囲むと、それらは1つのパラメーターとして扱われます。

 ./variables.sh「オタクにする」方法

2つのコマンドラインパラメーターを引用して、それらを1つのパラメーターとして処理する

オプション、引数付きのオプション、および「通常の」データ型パラメーターのすべての組み合わせを処理するスクリプトが必要な場合は、オプションを通常のパラメーターから分離する必要があります。 これは、引数の有無にかかわらず、すべてのオプションを通常のパラメーターの前に配置することで実現できます。

しかし、私たちが歩くことができる前に走らないようにしましょう。 コマンドラインオプションを処理するための最も単純なケースを見てみましょう。

取り扱いオプション

whileループでgetoptsを使用します。 ループの各反復は、スクリプトに渡された1つのオプションで機能します。 いずれの場合も、変数OPTIONgetoptsで識別されるオプションに設定されます。

ループが繰り返されるたびに、 getoptsは次のオプションに進みます。 これ以上オプションがない場合、 getoptsfalseを返し、 whileループは終了します。

Bashスクリプトでケースステートメントを使用する方法
関連するBashスクリプトでのケースステートメントの使用方法

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」を保持しますが、使用されるオプションと引数の数がわからない場合、スクリプトでどのようにアクセスしますか?

答えは、 OPTINDshiftコマンドを使用することです。

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準拠のネイティブスクリプトとまったく同じように、コマンドラインオプション、引数、およびパラメーターを処理するスクリプトを作成できます。