Bashプログラミング
 Computer >> コンピューター >  >> プログラミング >> Bashプログラミング

Bashスクリプトテンプレートの作成:再利用できる雛形づくりと実践的なテスト手法

このシリーズの最初の記事では、わずか1行の非常に小さなBashスクリプトを作成し、シェルスクリプトを作る理由や、コンパイル型プログラムではなくシェルスクリプトがシステム管理者にとって最も効率的な選択肢である理由について考察しました。

この2番目の記事では、他のBashスクリプトの出発点として使えるBashスクリプトテンプレートの作成を始めます。テンプレートには最終的に、ヘルプ機能、ライセンス文、いくつかの単純な関数、そしてコマンドラインオプションを処理するロジックなど、このテンプレートをベースとしたスクリプトで必要になりそうな要素が含まれることになります。

なぜテンプレートを作成するのか?

自動化全般と同じように、テンプレートを作成する背景にあるのは「怠惰なシステム管理者」であることです。テンプレートには、すべてのスクリプトに含めたい基本的な構成要素が入っています。新しいスクリプトごとにそれらの要素を追加するよりも時間を節約でき、新規スクリプトを簡単に始められます。

少数のコマンドラインのBashステートメントをファイルにまとめて実行可能にするだけで済ませたくなりますが、長い目で見るとそれは逆効果になることがあります。ヘルプ機能とコマンドラインオプションの受け付け能力を備えた、適切に書かれ適切にコメントされたBashプログラムは、そのプログラムを保守するシステム管理者にとって良い出発点となります。ここには、あなた自身が書き保守することになるプログラムも含まれます。

要件

取り組むすべてのプロジェクトに対して、必ず要件一式を作成すべきです。スクリプトの場合も同様で、たとえ2〜3項目だけの簡単なリストであっても例外ではありません。私は、要件定義書がない、あるいは内容が不十分だったことが原因で、完全に失敗したプロジェクトや顧客のニーズを満たせなかったプロジェクトに数多く携わってきました。

このBashテンプレートの要件は非常にシンプルです。

  1. 今後のBashプログラミングプロジェクトの出発点として使えるテンプレートを作成すること
  2. テンプレートは標準的なBashプログラミングの作法に従うこと
  3. 以下を含むこと:
    • プログラムの機能説明と変更履歴を記述できるヘッダーセクション
    • ライセンス文
    • 関数用のセクション
    • ヘルプ関数
    • プログラムの実行者がrootかどうかを確認する関数
    • コマンドラインオプションを評価する仕組み

基本構造

基本的なBashスクリプトには3つのセクションがあります。Bashにはセクションを明示的に区切る方法はありませんが、セクション間の境界は暗黙的に存在します。

  • すべてのスクリプトはシバン(#!)で始まる必要があり、これはどのBashプログラムにおいても最初の行でなければなりません。
  • 関数セクションはシバンの直後から、プログラム本体の前に置きます。何でも文書化したいという私の性分として、各関数の前にはその目的を簡潔に説明するコメントを置きます。関数内部にも、さらに詳しく説明するコメントを含めています。短くシンプルなプログラムには関数が不要な場合もあります。
  • プログラムのメイン部分は関数セクションの後に続きます。これは1つのBashステートメントでも、数千行のコードでもあり得ます。私のプログラムの一つには、コメントを除いて200行強のコードがあり、同じプログラムには600行以上のコメント行があります。

以上です。あらゆるBashプログラムの構造は、この3つのセクションだけです。

冒頭コメント

私はさまざまな理由から、これより多くの要素を必ず追加しています。まず、シバンの直後に数個のコメントセクションを追加します。これらのコメントセクションは任意ですが、非常に役立つと感じています。

最初のコメントセクションは、プログラム名と説明、そして変更履歴です。この形式はIBMで働いていた頃に学んだものであり、プログラムの長期的な開発経緯と適用された修正を文書化する手段となります。これはプログラムのドキュメント化における重要な第一歩です。

2番目のコメントセクションは、著作権とライセンスに関する声明です。私はGPLv2を使用しており、これはGPLv2でライセンスされるプログラムの標準的な声明と思われます。別のオープンソースライセンスを使うのも問題ありませんが、ライセンスに関する混乱を避けるため、コード内に明示的な声明を追加することをお勧めします。Scott Petersonの記事「The source code is the license(ソースコードこそがライセンスである)」が、この理由を説明する助けになります。

これでスクリプトは次のようになります。

#!/bin/bash
################################################################################
# scriptTemplate #
# #
# Use this template as the beginning of a new program. Place a short #
# description of the script here. #
# #
# Change History #
# 11/11/2019 David Both Original code. This is a template for creating #
# new Bash shell scripts. #
# Add new history entries as needed. #
# #
# #
################################################################################
################################################################################
################################################################################
# #
# Copyright (C) 2007, 2019 David Both #
# LinuxGeek46@both.org #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# #
################################################################################
################################################################################
################################################################################

echo "hello world!"

修正版のプログラムを実行して、期待どおりに動作していることを確認しましょう。

テストについて

ここでテストについて話すのに良いタイミングです。

「バグは常にあと1つ残っている。」

— Lubarskyのサイバネティック昆虫学の法則

Lubarsky氏が誰であれ、この言葉は正しいです。自分のコードからすべてのバグを見つけることは決してできません。私が見つけたバグごとに、さらに別のバグが出現するようで、しかも大抵は最悪のタイミングで現れます。

テストはプログラムだけに関わるものではありません。ハードウェア、ソフトウェア、あるいはユーザーが物事を壊すために見つける終わりのない方法によって引き起こされた問題が、実際に解決されたかどうかの検証にも関わります。それと同じくらい重要なのは、コードが使いやすく、インターフェイスがユーザーにとって理解しやすいことを保証することです。

シェルスクリプトの作成とテストにおいて明確に定義されたプロセスに従うことで、一貫性のある高品質な結果につながります。私のプロセスはシンプルです。

  1. 簡単なテスト計画を作成する。
  2. 開発のごく初期段階からテストを開始する。
  3. コード完成時に最終テストを行う。
  4. 本番環境へ移行し、さらにテストする。

テスト計画

テスト計画にはさまざまな形式があります。私は幅広い経験を持っています。すべて頭の中に入れておくやり方から、紙片に走り書きした数枚のメモ、そして各テストの詳細な説明、どの機能コードをテストするのか、テストで何を達成するのか、入力と結果がどうなるべきかまで求める複雑なフォーム一式まで扱ってきました。

かつてテスターだった(現在は違いますが)システム管理者として言えば、私は中間的な立場を取ろうとしています。少なくとも短い書面によるテスト計画があれば、テスト実行ごとの一貫性が確保されます。どれほどの詳細さが必要かは、開発とテストの体制がどれほど形式的かによります。

Googleで見つけたサンプルのテスト計画ドキュメントは複雑で、非常に形式的な開発・テストプロセスを持つ大規模組織向けでした。職名に「テスト」が付く人々には良いかもしれませんが、システム管理者のより混沌として時間に追われる労働状況にはうまく当てはまりません。仕事のほとんどの側面と同じように、システム管理者には創造性が必要です。そこで、テスト計画に含めるとよい項目の短いリストを示します。必要に応じて変更してください。

  • テスト対象ソフトウェアの名称と簡単な説明
  • テスト対象となるソフトウェア機能の説明
  • 各テストの初期条件
  • 各テストで実施する手順
  • 各テストの期待される結果の説明
  • 否定的な結果を検証するために設計された特定のテスト
  • 予期しない入力へのプログラムの対応を確認するテスト
  • 各テストにおける合否の基準の明確な説明
  • ファジーテスト(後述)

このリストがテスト計画を作成する際のヒントになれば幸いです。ほとんどのシステム管理者は、シンプルでやや非公式な形に留めるべきでしょう。

早くテスト、頻繁にテスト

私は常に、実行可能な最初の部分が完成した時点で、すぐにシェルスクリプトのテストを開始します。これは短いコマンドラインプログラムでも、実行ファイルとしてのスクリプトでも変わりません。

私は通常、新しいプログラムの作成をシェルスクリプトテンプレートから始めます。ヘルプ関数のコードを書いてテストします。これは通常プロセスの中で些細な部分ですが、作業を始めるきっかけになり、テンプレート内の要素が当初から正しく機能していることを保証してくれます。この段階なら、スクリプトのテンプレート部分の問題を修正したり、標準テンプレートでは満たせないニーズに合わせて変更したりするのが容易です。

テンプレートとヘルプ関数が機能するようになったら、プログラム仕様を満たすために必要なプログラミング手順を文書化するコメントを追加しながら、プログラム本体の作成に進みます。そして、各コメントに示された要件を満たすコードを追加していきます。このコードでは、テンプレートの該当セクションで初期化される変数の追加が必要になるでしょう。ここまで来ると、テンプレートは徐々にシェルスクリプトへと変わっていきます。

ここでのテストは、データを入力して結果を確認するだけのものではありません。少し余分な作業が必要です。時には、書いたばかりのコードの中間結果を単純に出力するコマンドを追加し、それを検証することがあります。より複雑なスクリプトでは、「テストモード」用の-tオプションを追加します。この場合、内部のテストコードはコマンドラインで-tオプションが指定されたときにのみ実行されます。

最終テスト

コードが完成したら、既知の入力を使って特定の出力を生成し、すべての機能について完全なテストを行います。また、ランダムな入力も試して、プログラムが予期しない入力に対応できるかを確認します。

最終テストは、プログラムが意図どおりに概ね機能していることを検証するためのものです。最終テストの大きな目的は、開発サイクルの早い段階で機能していた関数が、後から追加または変更されたコードによって壊されていないことを確認することです。

新しいコードを追加しながらテストを続けていれば、最終テストで驚きはないと思うかもしれません。それは間違いです。最終テストでは必ず驚きがあります。いつもです。その驚きを想定し、修正に時間をかける覚悟をしてください。もし最終テストでバグが一度も見つからなければ、最終テストを行う意味がないのではないでしょうか?

本番環境でのテスト

えっ、どういうこと?

「プログラムが本番稼働して少なくとも6ヶ月経つまで、最も有害なエラーは発見されない。」

— Troutmanのプログラミング公理

そうです、本番環境でのテストは今や正常で望ましいことと考えられています。私自身テスターだった経験からすると、これは理にかなっています。「ちょっと待ってください!危険では?」と言うでしょうね。私の経験では、専用のテスト環境での徹底的で厳密なテストより危険だということはありません。場合によっては、テスト環境が存在せず本番環境しかないため、選択の余地がないこともあります。

システム管理者にとって、新規または改訂版のスクリプトを本番環境でテストする必要性は馴染み深いものです。スクリプトが本番環境に移行されるときはいつでも、それが究極のテストとなります。本番環境こそがそのテストの最も重要な部分を占めます。テスターがテスト環境でどんなに工夫しても、真の本番環境を完全に再現することはできません。

「新しい」とされる本番環境でのテストという慣行は、システム管理者が昔から知っていたことの認知にすぎません。最高のテストは本番環境です。ただし、それが唯一のテストでない限りは。

ファジーテスト

これは、初めて聞いたときに目を丸くしたバズワードの一つです。その本質的な意味はシンプルで、「誰かにキーを叩きまくらせて何かを起こさせ、プログラムがそれにどう対処するかを見る」というものです。しかし、実際にはそれ以上のものがあります。

ファジーテストは、息子がゲームのコードをランダムな入力で1分足らずで壊したときのことに少し似ています。それにより、息子向けのゲーム作りの試みはほぼ終了しました。

ほとんどのテスト計画では、特定の結果や出力を生成する非常に具体的な入力を使用します。テストで成功と定義されるのが肯定的な結果であれ否定的な結果であれ、それでも制御されたものであり、入力と結果は特定され期待されるものです。例えば、特定の障害モードに対する特定のエラーメッセージなどです。

ファジーテストは、テストのあらゆる側面における無作為性への対処に関わります。例えば、初期条件、非常にランダムで予期しない入力、選択されたオプションのランダムな組み合わせ、低メモリ、他のプログラムとの高いCPU競合、テスト対象プログラムの複数インスタンス、テストに適用できるその他考えられるあらゆるランダムな条件などです。

私は最初からある程度のファジーテストを行うようにしています。Bashスクリプトがごく初期の段階で重大な無作為性に対応できないなら、コードを追加しても改善は見込めません。コードがまだ比較的シンプルなうちにこれらの問題を捕捉して修正する絶好の機会です。各段階で少しのファジーテストを行うことは、さらなるコードによって問題が覆い隠される前に発見するのにも有効です。

コード完成後には、より広範なファジーテストを行うのが好きです。必ず何らかのファジーテストを行いましょう。結果には確かに驚かされることがあります。期待されることをテストするのは簡単ですが、ユーザーはスクリプトに対して通常、期待されるような使い方をしません。

次回予告

この記事ではテンプレートの作成という点では少し進展しましたが、主にテストについて語りました。これは、テストがあらゆる種類のプログラム作成において重要な部分だからです。このシリーズの次の記事では、-hなどのオプションを検出して処理するコードとともに、基本的なヘルプ関数をBashスクリプトテンプレートに追加します。

関連リソース

  • Bashプログラミング入門:構文とツール
  • Bashプログラミング入門:論理演算子とシェル拡張
  • Bashプログラミング入門:ループ

この記事シリーズは、David Bothによる3部構成のLinux自習コース「Using and Administering Linux—Zero to SysAdmin」の第2巻第10章に一部基づいています。

  1. 星空観察の夜に役立つ!Linuxのナイトビジョン用Bashスクリプト「redscreen.sh」の使い方

    Linuxはサーバーや開発者の環境で使われることがよく話題になりますが、実は天文学の分野でも幅広く活用されています。Linux向けには、星図やスカイマップ、望遠鏡駆動システムを制御するインターフェースなど、天体観測に役立つツールが数多く存在します。しかし、天文学者にとって大きな課題のひとつが、暗闇の中で目の順応を保ちながらコンピューターを操作することです。 なぜ「暗順応」を守る必要があるのか 夜間の屋外で観測を行う際、天文学者は「暗順応(ダークアダプテーション)」と呼ばれる目の状態を維持しなければなりません。人間の目が薄暗い環境に完全に慣れるまでには、最大で30分ほどかかるとされています。とこ

  2. 実用的な5つの例で学ぶBashスクリプト入門チュートリアル

    Unix SedやUnix Awkシリーズと同様に、本シリーズではBashスクリプティングに関する記事を複数回にわたって公開します。実用的なサンプルを交えながら、Bashスクリプティングのテクニックを幅広く解説していきます。 シェルとは、ユーザーが入力したコマンドを解釈して実行するプログラムです。コマンドはユーザーが直接入力するか、「シェルスクリプト」と呼ばれるファイルから読み込まれます。 ユーザーからの入力を直接読み取る場合、そのシェルは対話型(インタラクティブ)シェルと呼ばれます。 一方、ファイルからコマンドを読み込んで実行する場合は非対話型(ノンインタラクティブ)シェルと呼ばれます。この