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

Bashシェルスクリプトで実現する自動化入門――システム管理者のための効率化ガイド

Linuxシステムの運用・管理に携わるシステム管理者(Sysadmin)には、業務を効率化するためのツールへのアクセス権があります。この記事シリーズでは、Bashシェルスクリプトによる自動化を通じて、これらのツールを最大限に活用し、日々の作業を楽にする方法を解説します。

取り上げる主なテーマは以下の通りです。

  • Bashシェルスクリプトによる自動化のメリット
  • CやC++などのコンパイル型言語よりも、システム管理者にとってシェルスクリプトが優れた選択である理由
  • 新しいスクリプトの要件定義の作成方法
  • コマンドラインインターフェース(CLI)プログラムから簡単なBashシェルスクリプトを作成する方法
  • スクリプトを実行するユーザーID(UID)を利用したセキュリティ強化
  • 論理比較ツールを使った実行フロー制御
  • コマンドラインオプションによるスクリプト機能の制御
  • スクリプト内の複数箇所から呼び出せるBash関数の作成
  • コードをオープンソースとしてライセンスする理由と方法
  • シンプルなテスト計画の作成と実施

筆者は以前、Bashコマンドと構文、そしてコマンドラインでのBashプログラム作成に関する一連の記事を執筆しました(本記事末尾の参考資料をご覧ください)。ただし、今回の全4回のシリーズは、Bashのコマンドや構文だけでなく、スクリプト作成そのもの、そして筆者が有用だと感じているテクニックについても扱います。

なぜ筆者はシェルスクリプトを使うのか

著書『The Linux Philosophy for Sysadmins』第9章で、筆者は次のように述べています。

「システム管理者が最も生産的になるのは、思考しているときだ。既存の問題の解決策や将来の問題の回避策を考え、Linuxコンピュータを監視して将来の問題を予兆する手がかりを見つける方法を考え、仕事をより効率化する方法を考え、毎日でも年1回でも必要となるすべてのタスクを自動化する方法を考えるときだ。」

「システム管理者が2番目に生産的になるのは、一見何もしていないように見えながら、自ら考案したソリューションを自動化するシェルプログラムを作成しているときだ。自動化の仕組みが整備されるほど、実際の問題が発生した際にそれを対処したり、さらに多くのタスクを自動化する方法を検討したりするための時間を確保できる。」

この初回の記事では、シェルスクリプトがなぜシステム管理者にとって重要なツールなのか、そしてごくシンプルなBashスクリプトを作成する基本について解説します。

なぜ自動化するのか?

コマンドラインで長く複雑なタスクを実行し終えたとき、「やっと終わった!もう二度と悩まされずに済む!」と思ったことはありませんか? 筆者は頻繁にそう感じてきました。しかし最終的に気づいたのは、コンピュータ上で行うほぼすべての作業(自分のマシンでも、雇用主や顧客の環境でも)は、将来いつかまた必要になるということです。

もちろん、その都度やり方を覚えていられると思っています。しかし、次に同じタスクが必要になるのはかなり先のことで、そもそも実行したことすら忘れてしまい、ましてや「どうやって」実行したかを思い出せることは稀です。筆者は当初、タスクの手順を紙切れに書き留めていましたが、やがて「なんて非効率なことを!」と思うようになりました。そこでメモをPC上のノートアプリに移しましたが、ある日また同じ考えが浮かびました。データをコンピュータに保存するなら、いっそ/usr/local/bin~/binといった標準的な場所にシェルスクリプトとして保存すればよいのです。そうすれば、プログラム名を入力するだけで、かつて手動で行っていたすべての作業を自動的に実行できます。

筆者にとって自動化とは、同じ作業を繰り返すために手順を記憶したり再現したりする必要がなくなるという意味もあります。やり方を思い出すにも、すべてのコマンドを入力するにも時間がかかります。長いコマンドを大量に入力するタスクでは、大きな時間の浪費になりかねません。シェルスクリプトによる自動化は、日常的なタスクのタイピング量を大幅に削減してくれます。

シェルスクリプトとは

シェルプログラム(いわゆるスクリプト)を書くことは、時間を最大限に活用するための最善の戦略です。一度書けば、必要なだけ何度でも再実行できます。さらに、Linuxのリリース間の変更への対応、ハードウェアやソフトウェアの追加、スクリプトで達成したい目標の変化、新機能の追加、不要機能の削除、そして決して珍しくないバグの修正など、スクリプトを柔軟に更新することも可能です。こうした変更は、あらゆる種類のコードにおける保守サイクルの一環です。

ターミナルでキーボードからシェルコマンドを入力・実行して行うすべてのタスクは、自動化できるし、自動化すべきです。システム管理者は、依頼された業務や必要性を判断した作業をすべて自動化すべきです。多くの場合、事前に自動化しておけば、最初の実行時点で時間の節約になります。

1つのBashスクリプトには、数個のコマンドから数千個のコマンドまで含められます。筆者は1〜2個のコマンドしか含まないスクリプトも書けば、半分以上がコメントである2,700行超のスクリプトも書いた経験があります。

はじめの一歩

ここでは、ごく単純なシェルスクリプトの例とその作成方法を紹介します。以前のシリーズでは、プログラミング入門書の定番である「Hello world」の例を使用しました。コマンドラインから実行すると、次のようになります。

[student@testvm1 ~]$ echo "Hello world"
Hello world

定義上、プログラムやシェルスクリプトとは、コンピュータに実行させる一連の命令です。しかし、毎回コマンドラインに打ち込むのは非常に面倒です。特にプログラムが長く複雑な場合はなおさらです。ファイルに保存しておけば、1つのコマンドで実行でき、時間の節約になり、エラーが混入するリスクも減らせます。

以下の例は、テストシステムや仮想マシン(VM)上で非rootユーザーとして試すことをお勧めします。例自体は無害ですが、ミスは起こるものであり、安全第一が賢明です。

まず、プログラムを格納するファイルを作成します。touchコマンドで空のファイルhelloを作成し、実行権限を付与します。

[student@testvm1 ~]$ touch hello
[student@testvm1 ~]$ chmod 774 hello

次に、お好みのエディタで次の行をファイルに追加します。

echo "Hello world"

ファイルを保存し、コマンドラインから実行します。このシリーズのスクリプトは、別のシェルセッションで実行することもできます。

[student@testvm1 ~]$ ./hello 
Hello world!

これはおそらく皆さんが作る中で最もシンプルなBashプログラム――ファイル内のたった1つのステートメントです。この演習では、このシンプルなステートメントを中心に完全なシェルスクリプトを組み立てていきます。プログラムの機能自体は重要ではなく、機能的なロジックを気にせずにプログラム構造――他のプログラムのためのテンプレート――を構築できます。基本的な構造とテンプレートの作成に集中し、複雑な機能を持つプログラムではなくテンプレート自体を作成・テストできるのがポイントです。

シバン(Shebang)

Bashまたはスクリプト内のコマンドと互換性のあるシェルを使用している限り、このステートメントは問題なく動作します。スクリプト内でシェルが指定されていない場合、デフォルトのシェルが使用されます。

次の課題は、別のシェルがデフォルトであっても、スクリプトが確実にBashで実行されるようにすることです。これを実現するのがシバン(shebang)行です。シバンとは、スクリプト実行時にどのシェルを使用するかを明示的に指定する#!という文字列を指す言葉です。この場合はBashですが、他の任意のシェルを指定することもできます。指定したシェルがインストールされていない場合、スクリプトは実行されません。

シバン行をスクリプトの1行目に追加すると、次のようになります。

#!/usr/bin/bash
echo "Hello world!"

もう一度スクリプトを実行してください。結果に違いはないはずです。ksh、csh、tcsh、zshなど他のシェルがインストールされている場合は、それらを起動して再度スクリプトを実行してみるとよいでしょう。

スクリプトとコンパイル型プログラムの違い

自動化のためのプログラムを書くとき、システム管理者は常にシェルスクリプトを使うべきです。シェルスクリプトはASCIIテキスト形式で保存されるため、人間もコンピュータと同様に容易に閲覧・修正できます。スクリプトの中身を見れば、何をするプログラムなのか、構文やロジックに明白なエラーがないかを正確に確認できます。これは「オープン」であることの意味を示す好例です。

一部の開発者は、シェルスクリプトを「真の」プログラミングではないとみなしているようです。これは、「真の」プログラミング言語とはソースコードから実行可能コードを生成するためにコンパイルが必要な言語のみだという考えに基づいているようですが、筆者の経験から断言できます。それは完全に誤りです。

筆者はBASIC、C、C++、Pascal、Perl、Tcl/Expect、REXX(Object REXXなどの派生版を含む)、Korn、csh、Bashなど多数のシェル言語、さらにはアセンブリ言語まで、さまざまな言語を使用してきました。これまでに考案されたすべてのコンピュータ言語には、共通の目的があります。それは、人間がコンピュータに何をすべきかを伝えることです。どの言語を選ぼうとも、プログラムを書くということは、特定のタスクを特定の順序で実行する指示をコンピュータに与えることに他なりません。

スクリプトは、コンパイル型言語よりもはるかに速く書けてテストできます。プログラムは通常、状況や上司が課す時間制約を満たすために迅速に作成しなければなりません。システム管理者が書くスクリプトの大半は、問題の修正、問題発生後の復旧、またはコンパイル型プログラムが完成するよりはるかに早く稼働させなければならないプログラムの提供のためのものです。

素早くプログラムを書くにはシェルプログラミングが最適です。それにより、顧客――それが自分自身であれ他の誰かであれ――のニーズに迅速に対応できます。ロジックの問題やバグがあれば、ほぼ即座に修正して再テストできます。要件定義に不備があれば、シェルスクリプトは新しい要件に合わせて短時間で変更できます。一般的に、システム管理者の仕事では開発スピードが、実行速度やRAMなどのシステムリソースの節約よりも優先されるのです。

システム管理者の作業のほとんどは、実際に実行することよりも、そのやり方を考えることに時間がかかります。したがって、すべての作業に対してシェルスクリプトを作成することは一見非効率に思えるかもしれません。スクリプトを書き、再現性のある結果を生み出すツールに仕上げるには時間がかかります。しかし、時間の節約は、やり方を改めて調べることなくスクリプトを実行できるたびに積み重なっていくのです。

まとめ

この記事ではシェルスクリプトの作成はそこまで深く掘り下げませんでしたが、非常に小さなスクリプトを1つ作成しました。また、シェルスクリプトを作成する理由と、それがコンパイル型プログラムではなくシステム管理者にとって最も効率的な選択肢である理由についても考察しました。

次回の記事では、他のBashスクリプトの出発点として使えるスクリプトテンプレートの作成を始めます。テンプレートには最終的に、ヘルプ機能、GNUライセンス表記、いくつかのシンプルな関数、オプションを処理するロジック、そしてこのテンプレートをベースとするスクリプトに必要となるその他の要素が含まれる予定です。

参考資料

  • How to program with Bash: Syntax and tools
  • How to program with Bash: Logical operators and shell expansions
  • How to program with Bash: Loops

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

  1. Bashシェル関数入門:実用的な6つのサンプル例で学ぶチュートリアル

    Bashシェル関数とは、複数のUNIX/Linuxコマンドをひとつの名前でグループ化し、後からまとめて実行できるようにする仕組みです。Bashシェル関数は通常のUnixコマンドと同じように呼び出すことができ、現在のシェルコンテキスト内で実行されるため、解釈用の新しいプロセスを生成する必要がありません。bashのエイリアス(alias)と関数はどちらも、長いコマンドや複雑なコマンドに対するショートカットを定義するのに役立ちます。しかし、エイリアスでは制御フローや引数の扱いなど、関数ならではの高度な処理を行うことはできません。本記事では、その違いも含めて詳しく解説していきます。この記事は、進行中の

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

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