ほとんどのシステム管理者にとって最も重要なツールの一つが自動化です。私たちは、日常的に頻繁に発生するタスクを自動化するために、スクリプトを作成・維持管理しています。
私は長年にわたり、大小さまざまな数十のスクリプトを作成・修正してきました。特に有用なスクリプトとしては、毎朝早い時間に定期的なバックアップを実行するもの、アップデートされて修正や機能強化を含むソフトウェアパッケージをインストールするもの、Fedora を最新バージョンにアップグレードするものなどがあります。数日前には、かなりシンプルなスクリプトを使って、個人用のホストとサーバーをすべて Fedora 34 にアップグレードしました。
スクリプトの作成時に特に頻繁に行っている作業は、ヘルプ関数の作成と GPL3 ライセンス・ステートメントを表示する関数の作成の 2 つです。問題が発生したときに特定しやすいよう、スクリプトには詳細モードやテストモードを含めるようにしています。一部のスクリプトでは、ユーザー名、アップグレードする Fedora のバージョン、ファイル名などの値も渡します。
この目的を達成する手法の一つが、スクリプト内の変数値として使うデータを指定する位置パラメーター (引数とも呼ばれる) を利用することです。もう一つはオプションとオプション引数の使用です。この記事ではこれら 2 つの手法、すなわち、スクリプトにデータを入力するための手法とスクリプトの実行経路を制御するための手法について説明します。
[ 今すぐダウンロード:システム管理者のための Bash スクリプトガイド ]
位置パラメーター
Bash は、コマンドラインから起動された際に Bash プログラムへデータを入力する手段として、位置パラメーターというツールを使用します。位置パラメーターは $0 から $9 までの 10 個存在しますが、この制限を回避する方法もあります。
まず、入力された名前を画面に表示する簡単なスクリプトから始めましょう。以下の内容で script1.sh というファイルを作成し、実行可能な状態にします。
#!/bin/bash echo $0 このスクリプトは、個人用の実行可能ファイルを保存するためのディレクトリである ~/bin directory に配置するとよいでしょう。$PATH 変数を確認してください。この変数には /home/username/bin が 1 つのコンポーネントとして含まれています。~/bin ディレクトリが存在しない場合は作成できます。あるいは、このファイルを任意の場所に配置し、そこで使用することも可能です。
次に、パラメーターなしでスクリプトを実行します。
[student@testvm1 ~]$ script1.sh /home/dboth/bin/script1.sh [student@testvm1 ~]$ このスクリプトはスクリプトの名前を出力します。$0 パラメーターは予約済みで、実行中のスクリプトの名前として事前に定義されており、他の目的には使用できません。これはスクリプト内で利用すると便利です。スクリプトが自身の名前を必要とする場合でも、スクリプトにそれを渡す必要がないからです。
では、位置変数に $1 を使用するようにスクリプトを変更し、もう一度実行します。
#!/bin/bash echo $1 今度は 1 つのパラメーターを使用してもう一度実行します。
[student@testvm1 ~]$ script1.sh help help [student@testvm1 ~]$ パラメーターが 2 語の場合はどうなるでしょうか。
[student@testvm1 ~]$ script1.sh help me help [student@testvm1 ~]$ これは 2 つのパラメーターとして処理されますが、以下のように引用符で囲むことで対処できます。
[student@testvm1 ~]$ script1.sh "help me" help me [student@testvm1 ~]$ たとえば、入力値が以下のように住所などの複数の単語から成る文字列の場合、これは便利です。
[student@testvm1 ~]$ script1.sh "80486 Intel St." 80486 Intel St. [student@testvm1 ~]$ しかし、名前や完全な住所などでは、複数のパラメーターが必要な場合もあります。
[ こちらもおすすめ:Bash のちょっと変わったテクニック:変数、find コマンド、ファイルディスクリプター、リモート操作など ]
プログラムを以下のように変更します。
#!/bin/bash echo "Name: $1" echo "Street: $2" echo "City: $3" echo "State/Province/Territory: $4" echo "Zip/Postal code: $5" そして、以下のパラメーターを使って実行します。
[student@testvm1 ~]$ script1.sh "David Both" "80486 Intel St."Raleigh NC XXXXX Name: David Both Street: 80486 Intel St. City: Raleigh State/Province/Territory: NC Zip/Postal code: XXXXX もちろん、値を割り当てた後の位置パラメーターはさまざまな方法で利用できますが、この小さなプログラムを使えば、その動作を簡単に理解できます。また、安全に試すことができます。
[ 無料ダウンロード:高度な Linux コマンドのチートシート ]
パラメーターの順序を変えて動作を確認してみてください。これらは位置を指定するパラメーターであり、その部分を考慮することが非常に重要です。必要なパラメーターの数、ユーザーがパラメーターをどのように記憶するか、パラメーターをどのように配置するべきかなどを考慮しなければなりません。
パラメーターの順番に依存しない方法が必要であり、実行経路を修正する方法も必要です。
オプション
これらの 2 つの操作は、コマンドラインオプションを使って実行できます。
単純な Bash プログラムであっても、またたとえかなり初歩的なものであったとしても、何らかのヘルプ機能を備えるべきだと私は考えています。私が作成する Bash シェルプログラムの多くは使用頻度が低いため、コマンドの正確な構文を忘れてしまうことがあります。また、非常に複雑なプログラムの場合は、頻繁に使用するものであっても、オプションや引数の要件を確認する必要があります。
ヘルプ関数が組み込まれていれば、コード自体を調べることなくそのような情報を確認できます。充実したヘルプ機能は、プログラムのドキュメント作成にも役立ちます。
関数について
シェル関数は、Bash プログラム・ステートメントのリストをシェル環境に保存したもので、コマンドラインで名前を入力することで他のコマンドと同様に実行できます。使用しているプログラミング言語によっては、シェル関数はプロシージャやサブルーチンと呼ばれることもあります。
[ 無料の Bash シェルスクリプト作成チートシートを入手 ]
関数は、他のコマンドと同様に、その名前を使うことでスクリプト内または CLI から呼び出されます。CLI プログラムやスクリプト内で関数が呼び出されると、関数内のコマンドが実行されます。その後、プログラムフローのシーケンスは呼び出し元に戻り、そのエンティティ内の次のプログラム・ステートメントが実行されます。
関数の構文は次の通りです。
FunctionName(){program statements}
CLI でシンプルな関数を作成してみましょう。関数は作成されたシェルインスタンスのシェル環境に保存されます。ここでは Hello world を意味する hw という関数を作成します。以下のコードを CLI に入力して Enter を押してください。その後、他のシェルコマンドと同様に hw と入力します。
[student@testvm1 ~]$ hw(){ echo "Hi there kiddo"; } [student@testvm1 ~]$ hw Hi there kiddo [student@testvm1 ~]$ さて、定番の「Hello world!」には少し飽きてきました。通常は から始めます。では、現在定義されている関数をすべてリストアップしましょう。たくさんあるので、新しい hw 関数だけを示しています。コマンドラインから、あるいはプログラム内で関数を呼び出すと、その関数はプログラムされたタスクを実行します。その後、関数は終了し、呼び出し元 (コマンドライン、またはスクリプト内の呼び出しステートメントの次の Bash プログラム・ステートメント) に制御を戻します。
[student@testvm1 ~]$ declare -f | less hw () { echo "Hi there kiddo" } では、この関数はもう必要ないので削除しましょう。unset コマンドで以下のように実行できます。
[student@testvm1 ~]$ unset -f hw ; hw bash: hw: command not found [student@testvm1 ~]$ hello.sh スクリプト
新しい Bash シェルスクリプト ~/bin/hello.sh を作成し、実行可能な状態にします。以下の内容を追加します。最初は基本的な内容に留めておきましょう。
#!/bin/bash echo "hello world!" 実行して、「hello world!」と表示されることを確認します。
[dboth@david ~]$ hello.sh hello world! [dboth@david ~]$ こちらのほうが落ち着くので、やっぱり「hello world!」にしましょう。
ヘルプ関数の作成
以下の help 関数を hello プログラムのコードに追加します。既存の 2 つのステートメントの間に help 関数を配置します。この help 関数は、プログラムの簡単な説明、構文図、利用できる各オプションの簡単な説明を表示します。また、help 関数をテストするための呼び出しと、関数とプログラムの主要部分を視覚的に区切るコメント行も追加します。
プログラムは以下のようになります。
#!/bin/bash ############################################################ # Help # ############################################################ Help() { # Display Help echo "Add description of the script functions here." echo echo "Syntax: scriptTemplate [-g|h|v|V]" echo "options:" echo "g Print the GPL license notification." echo "h Print this Help." echo "v Verbose mode." echo "V Print software version and exit." echo } ############################################################ ############################################################ # Main program # ############################################################ ############################################################ Help echo "Hello world!" この help 関数で説明されているオプションは、私が作成するプログラムでよく使用しているものです。ただし、いずれも現時点ではコードに実装されていません。プログラムを実行してテストしてみましょう。
[student@testvm1 ~]$ hello.sh Add a description of the script functions here. Syntax: scriptTemplate [-g|h|v|V] options: g Print the GPL license notification. h Print this Help. v Verbose mode. V Print software version and exit. Hello world! [student@testvm1 ~]$ 必要なときにヘルプを表示させるロジックをまだ追加していないため、このプログラムでは常にヘルプが表示されます。ただし、関数が正しく動作していることは確認できたので、次はプログラムのコマンドライン呼び出しで -h オプションを使用した場合にのみヘルプを表示させるロジックを追加します。
[ システム管理者スキルの力試しとして今すぐスキル評価を受けてみましょう ]
オプションの処理
Bash スクリプトは、ヘルプを表示する -h などのコマンドラインオプションを処理できるため、プログラムを制御し動作を修正する強力な機能を活用できます。これから実装する -h オプションでは、ヘルプテキストをターミナルセッションに表示した後、それ以外の処理を実行せずに終了するようプログラムします。コマンドラインで入力されたオプションを処理する機能を Bash スクリプトに追加するには、while コマンドと getops コマンド、case コマンドを組み合わせて使用します。
getops コマンドはコマンドラインで指定されたすべてのオプションを読み取り、そのオプションのリストを作成します。while コマンドは、以下のコードで各オプションに対して変数 $options を設定し、オプションのリストをループ処理します。case ステートメントでは各オプションを順番に評価し、対応するスタンザのステートメントを実行します。while ステートメントは、オプションのリストがすべて処理されるか、プログラムを終了させる exit ステートメントに遭遇するまで、オプションのリストの評価を続けます。
echo "Hello world!" ステートメントの直前にある help 関数の呼び出しを必ず削除してください。これで、プログラム本体は以下のようになります。
############################################################ ############################################################ # Main program # ############################################################ ############################################################ ############################################################ # Process the input options.Add options as needed. # ############################################################ # Get the options while getopts ":h" option; do case $option in h) # display Help Help exit;; esac done echo "Hello world!" -h の case オプションの exit ステートメントの末尾にある二重のセミコロンに注意してください。これは各オプションに必須です。この case ステートメントに追加することで、各オプションの終了を明示します。
テストは少し複雑になってきます。プログラムがどのように応答するかを確認するために、複数のオプション (およびオプションなし) でテストする必要があります。まず、オプションなしの場合に「Hello world!」が正しく表示されることを確認します。
[student@testvm1 ~]$ hello.sh Hello world! 問題なく動作したので、次にヘルプテキストを表示するロジックをテストします。
[student@testvm1 ~]$ hello.sh -h Add a description of the script functions here. Syntax: scriptTemplate [-g|h|t|v|V] options: g Print the GPL license notification. h Print this Help. v Verbose mode. V Print software version and exit. 想定通りに動作したので、今度は意図しないオプションを入力した場合の動作をテストしてみます。
[student@testvm1 ~]$ hello.sh -x Hello world! [student@testvm1 ~]$ hello.sh -q Hello world! [student@testvm1 ~]$ hello.sh -lkjsahdf Add a description of the script functions here. Syntax: scriptTemplate [-g|h|t|v|V] options: g Print the GPL license notification. h Print this Help. v Verbose mode. V Print software version and exit. [student@testvm1 ~]$ 無効なオプションの処理
このプログラムは、特定の応答を作成していないオプションについてはエラーを生成せずに単に無視します。ただし、最後の -lkjsahdf オプションでは、「h」が含まれているのでプログラムはこれを認識してヘルプテキストを表示しました。 テストの結果、不正確な入力が検出された場合にそれを処理してプログラムを終了する機能が欠けていることが判明しました。
明示的な一致条件に該当しないオプションに適用する別の case スタンザを case ステートメントに追加することができます。この汎用的な case は、特定の一致条件が指定されていないものすべてに一致します。修正した case ステートメントは以下のようになります。
while getopts ":h" option; do case $option in h) # display Help Help exit;; \?) # Invalid option echo "Error: Invalid option" exit;; esac done このコードがどのように動作するかについては説明が必要です。複雑に見えますが、理解は比較的容易です。while – done ストラクチャは、getopts – option ストラクチャ内の各オプションに対して 1 回ずつ実行されるループを定義します。":h" 文字列 (引用符が必要) は、case – esac ストラクチャによって評価される入力オプションの候補をリストします。リストされた各オプションには、case ステートメント内で対応するスタンザが必要です。現在は 2 つあります。1 つは Help プロシージャを呼び出す h) スタンザです。Help プロシージャが完了すると、実行は次のプログラム・ステートメント exit;; に戻り、コードが存在する場合でもそれ以上コードを実行せずにプログラムを終了します。オプション処理ループも終了するため、追加のオプションはチェックされません。
case ステートメントの最後のスタンザとして \? による catch-all が設定されている点に注意してください。認識されないオプションが入力された場合、このスタンザは短いエラーメッセージを表示し、プログラムを終了します。
以後 case を追加する場合は、catch-all の前に配置する必要があります。私は case スタンザをアルファベット順に並べるのが好きなのですが、特定の case が他の case よりも先に処理されるようにしたい場合もあります。case ステートメントは上から順に処理されるので、プログラム作成時にはそれを意識する必要があります。
case コンストラクトの各スタンザの最終ステートメントは、スタンザ末尾を明示的に示す二重セミコロン (;;) で終わる必要があります。これにより、各ステートメントの末尾に (暗黙のセミコロンではなく) 明示的なセミコロンを使用したい人も、case スタンザ内のステートメントで同様にセミコロンを使用できます。
以前と同じオプションを使ってプログラムを再度テストし、動作を確認します。
Bash スクリプトは、以下のようになります。
#!/bin/bash ############################################################ # Help # ############################################################ Help() { # Display Help echo "Add description of the script functions here." echo echo "Syntax: scriptTemplate [-g|h|v|V]" echo "options:" echo "g Print the GPL license notification." echo "h Print this Help." echo "v Verbose mode." echo "V Print software version and exit." echo } ############################################################ ############################################################ # Main program # ############################################################ ############################################################ ############################################################ # Process the input options.Add options as needed. # ############################################################ # Get the options while getopts ":h" option; do case $option in h) # display Help Help exit;; \?) # Invalid option echo "Error: Invalid option" exit;; esac done echo "hello world!" プログラムのこのバージョンは徹底的にテストしてください。ランダムな入力を使って動作を確認しましょう。また、先頭にダッシュ (-) を付けずに、有効なオプションと無効なオプションの両方を試してみてください。
オプションを使ったデータ入力
まず、変数を追加して初期化します。以下のプログラムのセグメントに、太字で示されている 2 行を追加します。これにより、$Name 変数が「world」をデフォルト値として初期化されます。
############################################################ ############################################################ # Main program # ############################################################ ############################################################ # Set variables Name="world" ############################################################ # Process the input options.Add options as needed. # プログラムの最終行である echo コマンドを以下のように変更します。
echo "hello $Name!" 名前を入力するロジックは後ほど追加しますが、まずはプログラムを再度テストしてください。結果は以前とまったく同じになるはずです。
[dboth@david ~]$ hello.sh hello world! [dboth@david ~]$ # Get the options while getopts ":hn:" option; do case $option in h) # display Help Help exit;; n) # Enter a name Name=$OPTARG;; \?) # Invalid option echo "Error: Invalid option" exit;; esac done $OPTARG は、新しいオプション引数がいくつあっても常にその変数名として使用されます。$OPTARG の値は、プログラムの残りの部分で使用される変数名に割り当てる必要があります。この新しいスタンザには exit ステートメントがありません。これによりプログラムフローが変更され、case ステートメント内のすべての有効なオプションが処理された後、実行が case コンストラクトの後の次のステートメントに移ります。
修正したプログラムをテストします。
[dboth@david ~]$ hello.sh hello world! [dboth@david ~]$ hello.sh -n LinuxGeek46 hello LinuxGeek46! [dboth@david ~]$ hello.sh -n "David Both" hello David Both! [dboth@david ~]$ 完成したプログラムは以下のようになります。
#!/bin/bash ############################################################ # Help # ############################################################ Help() { # Display Help echo "Add description of the script functions here." echo echo "Syntax: scriptTemplate [-g|h|v|V]" echo "options:" echo "g Print the GPL license notification." echo "h Print this Help." echo "v Verbose mode." echo "V Print software version and exit." echo } ############################################################ ############################################################ # Main program # ############################################################ ############################################################ # Set variables Name="world" ############################################################ # Process the input options.Add options as needed. # ############################################################ # Get the options while getopts ":hn:" option; do case $option in h) # display Help Help exit;; n) # Enter a name Name=$OPTARG;; \?) # Invalid option echo "Error: Invalid option" exit;; esac done echo "hello $Name!" ヘルプ機能と、無効な入力に対するプログラムの反応をテストし、処理能力が損なわれていないことを確認してください。すべて正常に動作すれば、オプションとオプション引数の使い方を正しく理解できたことになります。
まとめ
この記事では、コマンドラインからの呼び出し時に Bash プログラムにデータを入力するための位置パラメーターと、プログラムフローの制御やプログラムへのデータ入力のためのオプションを使用しました。また、ヘルプ関数と、コマンドラインオプションを処理してヘルプを選択的に表示させる機能を追加しました。さらに、コマンドラインで名前を入力できるようにするオプション引数も追加しました。
この小さなテストプログラムはシンプルに設計されているため、この入力手法をご自身で簡単に試すことができます。練習として、姓と名を取得するようにプログラムを修正してみましょう。姓と名のオプションを逆順に入力するとどうなるか、試してみてください。
関連資料
執筆者紹介
David Both is an open source software and GNU/Linux advocate, trainer,
writer, and speaker who lives in Raleigh, NC. He is a strong
proponent of and evangelist for the "Linux Philosophy."
David has been in the IT industry for over 50 years. He has taught RHCE
classes for Red Hat and has worked at MCI Worldcom, Cisco, and the State
of North Carolina. He has been working with Linux and open source
software for over 20 years.
David likes to purchase the components and build his own computers from
scratch to ensure that each new computer meets his exacting
specifications. His primary workstation is an ASUS TUF X299 motherboard
and an Intel i9 CPU with 16 cores (32 CPUs) and 64GB of RAM in a
CoolerMaster MasterFrame 700.
David has written articles for magazines including Linux Magazine and
Linux Journal. His article "Complete Kickstart," co-authored with a
colleague at Cisco, was ranked 9th in the Linux Magazine Top Ten Best
System Administration Articles list for 2008. David currently writes
prolifically for OpenSource.com and Enable Sysadmin.
David currently has five books published with Apress, "The Linux
Philosophy for SysAdmins," a self-study training course in three
volumes "Using and Administering Linux: Zero to SysAdmin," that was
released in late 2019, and "Linux for Small Business Owners" with
co-author Cyndi Bulka.
David can be reached at LinuxGeek46@both.org or on Twitter @LinuxGeek46.
類似検索
Refactoring isn’t just technical—it’s an economic hedge
Streamline your network operations with Red Hat Ansible Automation Platform and Cisco Meraki
Technically Speaking | Taming AI agents with observability
Transforming Your Identity Management | Code Comments
チャンネル別に見る
自動化
テクノロジー、チームおよび環境に関する IT 自動化の最新情報
AI (人工知能)
お客様が AI ワークロードをどこでも自由に実行することを可能にするプラットフォームについてのアップデート
オープン・ハイブリッドクラウド
ハイブリッドクラウドで柔軟に未来を築く方法をご確認ください。
セキュリティ
環境やテクノロジー全体に及ぶリスクを軽減する方法に関する最新情報
エッジコンピューティング
エッジでの運用を単純化するプラットフォームのアップデート
インフラストラクチャ
世界有数のエンタープライズ向け Linux プラットフォームの最新情報
アプリケーション
アプリケーションの最も困難な課題に対する Red Hat ソリューションの詳細
仮想化
オンプレミスまたは複数クラウドでのワークロードに対応するエンタープライズ仮想化の将来についてご覧ください