シェルとは、オペレーティングシステムのコマンドインタプリタのことです。 Bash は私のお気に入りのシェルですが、すべての Linux シェルは、ユーザーまたはシステム管理者が入力したコマンドを、オペレーティングシステムが使用できる形に解釈しています。 その結果がシェルプログラムに返されると、シェルプログラムはそれをSTDOUTに送り、デフォルトではターミナルに表示します。
タブ補完、コマンドラインの呼び出しと編集、エイリアスなどのショートカットなどの機能はすべて、強力なシェルとしての価値に貢献している。 デフォルトのコマンドライン編集モードは Emacs を使用しますが、私のお気に入りの Bash の特徴の 1 つは、Vi モードに変更して、すでに自分のマッスル メモリの一部となっている編集コマンドを使用できることです。 この連載のベースとなった 3 巻の Linux 自己学習コースを研究している間に、20 年以上 Linux を扱ってきて知らなかったことを Bash について学びました。 この新しい知識のいくつかは、プログラミング言語としてのBashの使用に関するものです。 Bash は強力なプログラミング言語であり、コマンドラインやシェルスクリプトで使用するために完璧に設計されています。
この 3 部構成のシリーズでは、コマンドラインインターフェース (CLI) プログラミング言語として Bash を使用することを検討します。 この最初の記事では、Bash、変数、および制御演算子を使用したいくつかの簡単なコマンドライン プログラミングについて見ていきます。 他の記事では、Bashファイルの種類、実行フロー制御ロジックを提供する文字列、数値、その他の論理演算子、さまざまなタイプのシェル拡張、および反復操作を可能にするfor、while、untilループについて説明します。 また、これらのツールの使用を簡略化し、サポートするいくつかのコマンドも紹介します。
The shell
A shell is the command interpreter for the operating system. Bash は私のお気に入りのシェルですが、すべての Linux シェルは、ユーザーまたはシステム管理者が入力したコマンドを、オペレーティング・システムが使用できる形式に解釈します。 その結果がシェルプログラムに返されると、ターミナルに表示されます。
BashはBourne Again Shellの略で、Bashシェルは1977年にSteven Bourneによって書かれた古いBourneシェルをベースにしているからです。 他にも多くのシェルがありますが、私がよく遭遇するのはこの4つです:
- csh: C 言語の構文が好きなプログラマのための C シェル
- ksh: David Korn によって書かれ、Unix ユーザに人気のある Korn シェル
- tcsh。 csh の使いやすさを向上させたバージョン
- zsh。 他の有名なシェルの多くの機能を組み合わせた Z シェル
すべてのシェルには、コアユーティリティが提供するものを補足したり置き換えたりするコマンドが組み込まれています。 シェルの man ページを開いて、それが提供するコマンドを見るために “BUILT-INS” セクションを見つけなさい。 あるものは他のものよりうまく機能するでしょう。 私は C シェル、Korn シェル、そして Z シェルを使ってきました。 今でもBashシェルはそのどれよりも好きです。 他のシェルを試す必要があるかもしれませんが、自分に一番合うものを使ってください。 幸いなことに、シェルの変更は非常に簡単です。
これらのシェルはすべてプログラミング言語であり、コマンドインタプリタでもあります。 ここでは、Bash の不可欠な部分であるいくつかのプログラミング構造とツールについて簡単に説明します。
Bash as a programming language
多くのシステム管理者は、通常かなり単純で簡単なコマンドを発行するために Bash を使用してきました。 しかし、Bash は単一のコマンドを入力する以上のことができ、多くのシステム管理者は一連のタスクを実行するためのシンプルなコマンドライン プログラムを作成します。 これらのプログラムは時間と労力を節約できる共通のツールです。
CLIプログラムを書くときの私の目的は、時間と労力を節約することです (すなわち、怠惰なシスアドになることです)。 CLI プログラムは、いくつかのコマンドを特定の順序でリストアップし、次々と実行することでこれをサポートします。したがって、あるコマンドの進行状況を見たり、最初のコマンドが終了したら次のコマンドを入力したりする必要がありません。 そのため、1 つのコマンドの進行状況を監視し、最初のコマンドが終了したら次のコマンドを入力する必要がありません。
「プログラム」とは何ですか。 “コンピュータによって実行される命令であり、それらが実行される物理的な装置とは対照的である” と定義しています。 プリンストン大学のWordNetは、プログラムを次のように定義しています。 “コンピュータが解釈し実行できる一連の命令…” Wikipedia にもコンピュータ・プログラムに関する良い項目があります。
したがって、プログラムは、特定の関連タスクを実行する 1 つ以上の命令で構成されることがあります。 コンピュータプログラムの命令は、プログラムステートメントとも呼ばれます。 シスアドにとって、プログラムは通常シェルコマンドのシーケンスです。 Linux で利用できるすべてのシェル、少なくとも私が知っているシェルは、少なくとも基本的なプログラミング機能を備えており、ほとんどの Linux ディストリビューションのデフォルトシェルである Bash も例外ではありません。 シェルによっては、他のシェルがサポートしていない機能をサポートしている場合もありますが、いずれも何らかのプログラミング機能を備えています。 シェルプログラムはファイルに保存して繰り返し使用することもできますし、必要に応じてコマンドラインで作成することもできます。
Simple CLI programs
最も単純なコマンドライン プログラムは、Enter キーを押す前にコマンドラインで入力する、関連するかしないかの 1 つか 2 つの連続したプログラム文です。 プログラムの 2 番目のステートメントは、もしあれば最初のステートメントの動作に依存するかもしれませんが、依存する必要はありません。 コマンド ラインに 1 つのコマンドを入力する場合、Enter キーを押すと、暗黙のうちにセミコロン (;) が付いてコマンドが終了します。 コマンドラインに1行で入力されるCLIシェル・プログラムで使用する場合は、セミコロンを使用して各文を終了させ、次の文と区切らなければなりません。 CLI シェル・プログラムの最後のステートメントでは、明示的または暗示的なセミコロンを使用できます。
Some basic syntax
次の例では、この構文を明確にします。 このプログラムは、明示的なターミネーターを持つ 1 つのコマンドで構成されています。
$ echo "Hello world." ;
Hello world.
これは大したプログラムではないように見えるかもしれませんが、私が新しいプログラミング言語を学ぶたびに最初に遭遇するプログラムなのです。 構文は言語ごとに少し異なるかもしれませんが、結果は同じです。
このつまらない、しかしどこにでもあるようなプログラムを少し拡大してみましょう。 あなたの結果は、私が他の実験を行ったので、私と異なるでしょう。一方、あなたは、GUI デスクトップ経由でアカウントに初めてログインしたときに、アカウントのホーム ディレクトリに作成されるデフォルト ディレクトリとファイルだけを持っているかもしれません。
$ echo "My home directory." ; ls ;
My home directory.
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
それは少し意味がありますね。 結果は関連していますが、個々のプログラム ステートメントは互いに独立しています。 セミコロンの前後にスペースを入れるのが好きなのは、コードが少し読みやすくなるからです。
$ echo "My home directory." ; ls
出力に違いはありません。
Something about variables
すべてのプログラミング言語と同様に、Bash シェルは変数を扱うことができます。 変数とは、ある種の値を含むメモリ上の特定の場所を参照する記号的な名前である。
BashはCや関連言語のように変数を型付けせず、整数、浮動小数点、文字列型として定義する。 Bashでは、すべての変数は文字列である。 整数である文字列は整数演算で使うことができ、これはBashができる唯一のタイプの数学である。 より複雑な計算が必要な場合は、CLI プログラムとスクリプトで bc コマンドを使用できます。
変数は値が割り当てられ、CLI プログラムとスクリプトでそれらの値を参照するために使用できます。 変数の値はその名前を用いて設定しますが、$記号は付けません。 VAR=10という代入は、変数VARの値を10に設定する。 変数の値を表示するには、echo $VARというステートメントを使用します。
Bashの変数は,設定を解除するまでシェル環境の一部となります。 その後、変数に値を代入し、それを表示してその値を確認します。
$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
Hello World
$
注意:変数の代入の構文は非常に厳密です。 代入文の等号(=)の両側にスペースがあってはなりません。
空の行は、MyVarの初期値がNULLであることを示します。 変数の値の変更と設定も同じように行います。 この例では、元の値と新しい値の両方を示しています。
前述のように、Bashは整数演算を行うことができるので、配列内の要素の位置への参照を計算したり、簡単な計算問題を行ったりするのに便利です。 科学計算や金融計算のような小数を必要とするものには向いていません。
ここで簡単な計算をしてみましょう。
$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
Result = 63
浮動小数点数という結果になる計算を実行するとどうなりますか?
結果は最も近い整数になります。 計算がecho文の一部として実行されたことに注目してください。 Bash の優先順位により、計算が echo コマンドを囲む前に実行されます。 詳細は Bash man page で “precedence” を検索してください。
制御演算子
シェル制御演算子は、面白いコマンドライン・プログラムを簡単に作るための構文演算子の一つです。 CLI プログラムの最も単純な形式は、コマンド ライン上にいくつかのコマンドを順番に並べるだけです:
command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;
これらのコマンドは、エラーが発生しない限り、すべて問題なく実行されます。 しかし、エラーが発生するとどうなるのだろうか。 組み込みの&&と||Bash制御演算子を使って、エラーを予期し許容することができる。 この2つの制御演算子はフロー制御を行い、コードの実行順序を変更することができる。 セミコロンも、改行文字と同様に Bash 制御演算子とみなされます。
&演算子は、単に「もし command1 が成功したら command2 を実行し、もし command1 が何らかの理由で失敗したら command2 はスキップする」と言うものです。 この構文は次のようになります:
command1 && command2
さて、新しいディレクトリを作成し、成功したらそれを現在の作業ディレクトリ (PWD) にするいくつかのコマンドを見てみましょう。 あなたのホームディレクトリ(~)がPWDであることを確認してください。
The error was emitted by the mkdir command.このコマンドは、/rootというアクセス権のないディレクトリで最初に試してください。 ディレクトリの作成に失敗したため、ファイルを作成できなかったことを示すエラーは出ていません。 &&制御演算子は0以外のリターンコードを感知したため、touchコマンドはスキップされました。 &&制御演算子を使用すると、ディレクトリの作成に失敗したため、touchコマンドを実行できないようにすることができる。 このようなコマンドライン・プログラムのフロー制御は、エラーが複合的になって物事を本当に混乱させることを防ぐことができます。
|| 制御演算子を使用すると、最初のプログラム文が 0 より大きいコードを返したときに実行する別のプログラム文を追加することができます。 基本的な構文は次のようになります。
command1 || command2
この構文は、”コマンド 1 が失敗したら、コマンド 2 を実行します” と読み取ります。 これは、command1が成功したら、command2はスキップされることを意味します。 新しいディレクトリを作成しようとして試してみてください:
これはまさにあなたが期待するものです。 新しいディレクトリを作成できなかったので、最初のコマンドは失敗し、その結果 2 番目のコマンドが実行されました。
これら 2 つの演算子を組み合わせることで、両方の長所が発揮されます。 何らかのフロー制御を使用する制御演算子の構文は、&&と||制御演算子が使用される場合、この一般的な形になる:
preceding commands ; command1 && command2 || command3 ; following commands
この構文は、次のように記述することができる。 “コマンド1がリターンコード0で終了したら、コマンド2を実行し、そうでなければコマンド3を実行する。” 試してみましょう:
ここで、/rootディレクトリの代わりにホームディレクトリを使用して、最後のコマンドをもう一度試してみてください。 このディレクトリを作成する権限があります:
$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
$
コマンド1 && コマンド2のような制御演算子の構文は、すべてのコマンドが正常に完了したか、実行中に何らかの失敗があったかどうかを示す戻りコード (RC) をシェルに送信するため、動作します。 慣習的に、RCが0(ゼロ)であれば成功を示し、正の数であれば何らかの失敗を示します。 システム管理者が使用するツールの中には、失敗を示すために単に1を返すものもあるが、多くは発生した失敗の種類を示すために他のコードを使用する。
Bashシェル変数$? この RC は、スクリプトやコマンドリストの次のコマンド、あるいはシステム管理者が直接、非常に簡単に確認することができる。 まずは簡単なコマンドを実行し、すぐにRCをチェックしてみよう。 RC は常に、それを見る前に実行された最後のコマンドのものです。
この場合の RC は 0 で、これはコマンドが正常に完了したことを意味します。
この場合、RCは2です。これは、root以外のユーザーがアクセスを許可されていないディレクトリにアクセスするための許可が拒否されたことを意味します。 制御演算子はこれらの RC を使用して、プログラムの実行順序を変更できるようにします。
Summary
この記事では、プログラミング言語としての Bash を取り上げ、その基本構文といくつかの基本ツールについて探りました。 STDOUT にデータを出力する方法と、変数と制御演算子を使用する方法を示しました。 このシリーズの次の記事では、命令実行の流れを制御する多くの Bash 論理演算子のいくつかを見ていきます。