第18章 Bash と Bash スクリプト

目次

18.1. シェル とは?
18.2. シェルスクリプトの作成
18.3. コマンドイベントのリダイレクト
18.4. 別名定義の使用
18.5. Bash 内での変数の使用
18.6. コマンドのグループ化と組み合わせ
18.7. 一般的なフロー制御
18.8. さらなる情報

概要

今日、多くの人々が KDE や GNOME のようなグラフィカルユーザインターフェイス (GUI) を利用してコンピュータを操作しています。コンピュータは多くの機能を 提供しているにもかかわらず、自動的な作業の実行となると、 GUI の用途は限られた ものになってしまいます。シェルは GUI に足りない部分を埋めるには良いもので、 本章ではシェルまわりの概要について、特に bash 関連について述べています。

18.1. シェル とは?

伝統的な観点では、 シェル とは Bash (Bourne again Shell) のことを指します。本章で シェル と記述した場合も 同じで、 Bash のことを指します。実際には Bash 以外にも多くのものがあります (ash, csh, ksh, zsh, …) が、それぞれは異なる機能と特徴を持っています。 他のシェルについて詳しい情報を得たい場合は、 YaST 内で シェル を検索してください。

18.1.1. Bash の設定ファイルについての知識

シェルはそれぞれ下記の方法で起動することができます:

  1. 対話的なログインシェルとして。マシンにログインする際に使用されている方法で、 Bash に --login オプションを付けて起動するか、もしくは SSH でリモートコンピュータからログインしたときなどに使用することができる ものです。

  2. 通常の 対話シェルとして。xterm や konsole, gnome-terminal などのツールを利用して開始した場合に当てはまります。

  3. 非対話シェルとして。これはコマンドラインからシェルスクリプトを起動したり した場合に当てはまります。

どの種類のシェルを利用するのかによって、シェルはそれぞれ異なる設定ファイルを 読み込む仕組みになっています。下記の表には、ログインシェル/非ログインシェル として利用する場合に利用することのできる設定ファイルを示しています。

表18.1 ログインシェルとして使用する際の Bash 設定ファイル

ファイル

説明

/etc/profile

このファイルを修正してはいけません。修正しても次のアプリケーション 更新で修正内容が上書きされてしまいます!

/etc/profile.local

/etc/profile に対して何らかの設定を行ないたい 場合は、このファイルに記述します。

/etc/profile.d/

プログラム固有のシステム全体向け設定ファイルが含まれています。

~/.profile

ログインシェルとして使用する場合に、各ユーザが設定したい 項目があれば、ここに記述します。


表18.2 ログインシェル以外で使用する際の Bash 設定ファイル

/etc/bash.bashrc

このファイルを修正してはいけません。修正しても次のアプリケーション 更新で修正内容が上書きされてしまいます!

/etc/bash.bashrc.local

Bash だけに対して何らかの設定を行ないたい場合は、このファイルに 記述します。

~/.bashrc

ユーザ単位での設定は、このファイルに記述します。


また、 Bash では下記のファイルも使用します:

表18.3 Bash 向けの特殊ファイル

ファイル

説明

~/.bash_history

以前に入力した全てのコマンドについて、一覧を保持しています。

~/.bash_logout

ログアウト時に実行する内容を記述します。


18.1.2. ディレクトリ構造

下記の表には、 Linux システムにある最上位のディレクトリのうち、 最も重要なものについて簡単な説明を示しています。また、ディレクトリに関する さらに詳しい情報と、重要なサブディレクトリについては、続く表で説明しています。

表18.4 標準的なディレクトリ構造の概要

ディレクトリ

内容

/

ルートディレクトリと呼ばれるディレクトリです。 ディレクトリのツリー (木) 構造の開始点です。

/bin

システム管理者と一般のユーザの両方が利用する、重要な バイナリファイル (コマンド) 群が含まれるディレクトリです。 通常は bash などのシェルもこの中に含まれます。

/boot

ブートローダで利用するファイルなどが含まれるディレクトリです。

/dev

そのマシン固有のデバイス情報にアクセスするためのディレクトリです。

/etc

そのマシン固有のシステム設定ファイルが含まれるディレクトリです。

/home

このシステムでアカウントを持つ全てのユーザに対して設定する、 ホームディレクトリの開始点です。 root のホームディレクトリ については例外的に /home ではなく /root にホームディレクトリが設定されています。

/lib

重要な共有ライブラリとカーネルモジュールが含まれるディレクトリです。

/media

リムーバブル (取り外し可能な) メディアのマウントポイントです。

/mnt

一時的にファイルシステムにマウントする際に利用するディレクトリです。

/opt

追加のソフトウエアパッケージをインストールするディレクトリです。

/root

スーパーユーザ root のホームディレクトリです。

/sbin

重要なシステムバイナリファイルが含まれるディレクトリです。

/srv

システムが提供する各種サービスのデータを保管するディレクトリです。

/tmp

一時 (テンポラリ) ファイル向けのディレクトリです。

/usr

読み込みのみのデータが含まれる、階層の開始点です。

/var

ログファイルなどの可変データが含まれるディレクトリです。

/windows

システムに Microsoft Windows* と Linux の両方がインストール されている場合にのみ利用できます。 Windows 側のデータに アクセスできるディレクトリです。


また、下記の一覧にはより詳しい情報のほか、それらのディレクトリ内に 存在するファイルやサブディレクトリの例を挙げています:

/bin

root や他のユーザが利用する、基本的なシェルコマンドが含まれています。 このディレクトリに存在するコマンドとしては、 ls, mkdir, cp, mv, rm, rmdir などがあります。 また、 /bin には openSUSE の既定のシェルである bash も含まれています。

/boot

ブートローダやカーネルなどの起動に必要なデータのほか、カーネルが通常の プログラムを起動する前に使用する各種のデータが含まれています。

/dev

ハードウエア部品を表わす、デバイスファイルが含まれています。

/etc

X ウインドウシステムなどのプログラムを操作するのに必要な、各コンピュータ 固有の設定ファイルが含まれています。たとえば /etc/init.d には、起動処理中に実行する各種スクリプト が含まれています。

/home/username

そのシステムにアカウントを持つそれぞれのユーザに対して、各ユーザの個人 データを保持するディレクトリです。このディレクトリ以下にあるファイルは、 そのファイルの所有者かシステム管理者だけが変更することができます。 既定では、電子メールや個人のデスクトップ設定などが隠しファイルや ディレクトリの形で保存されます。 KDE ユーザの場合、デスクトップの 個人設定は .kde4 のディレクトリに、 GNOME ユーザの 場合は .gconf 内にそれぞれ保存されます。

[Note]ネットワーク環境でのホームディレクトリ

ネットワーク環境で作業を行なっている場合、お使いのホームディレクトリは /home 以外のディレクトリに割り当てられている 場合もあります。

/lib

システムを起動したり、ルートファイルシステム内でコマンドを実行したり する際に必要となる、重要な共有ライブラリが含まれています。 共有ライブラリとは、 Windows で言うところの DLL ファイルのことです。

/media

CD-ROM や USB メモリ、デジタルカメラ (USB 接続の場合) など、 リムーバブルメディアに対するマウントポイントです。 /media は、お使いのシステムに内蔵されているハードディスクを除く、全ての ドライブをマウントするための場所です。リムーバブルメディアを挿入したり 接続したりするとマウントされますので、ここからアクセスすることができます。

/mnt

一時的にファイルシステムをマウントしたい場合に利用するマウントポイントです。 このディレクトリに root がマウントを行なう場合もあります。

/opt

サードパーティ製のソフトウエアをインストールするための予約されている領域です。 オプションのソフトウエアや、巨大なアドオンプログラムパッケージが それぞれ配置されます。

/root

root ユーザのホームディレクトリです。 root の個人的な データがここに配置されます。

/sbin

s が示しているとおり、このディレクトリにはスーパーユーザ 向けの各種ユーティリティが含まれています。 /sbin には、 /bin に追加する形で、システムの起動や復元、修復などの 各種バイナリ (実行形式) ファイルが含まれています。

/srv

システムが提供する各種サービス、たとえば FTP や HTTP などに使用する データが含まれています。

/tmp

このディレクトリは任意のプログラムから使用されるディレクトリで、 一時的にファイルを作成する場所として使用しています。

[Important]起動時における /tmp のクリーンアップ

/tmp 内に保存されたデータは、システム再起動が 行なわれると削除される可能性があります。これは /etc/sysconfig/cron などの設定に依存して決まります。

/usr

/usrユーザ の略ではなく、 UNIX system resources (UNIX システムリソース) の略です。 /usr 内にあるデータは Filesystem Hierarchy Standard (FHS) 仕様を満たす様々なコンピュータで共有できるもので、静的な 読み込みだけを行なう目的のファイルが配置されます。 このディレクトリには全てのアプリケーションプログラムが配置され、 ファイルシステム内での第 2 の場所として機能しています。 KDE4 と GNOME についてもこちらに配置されます。 /usr には複数のサブディレクトリが含まれます。それぞれ /usr/bin, /usr/sbin, /usr/local, /usr/share/doc などがあります。

/usr/bin

一般ユーザから利用できるプログラムが含まれます、

/usr/sbin

修復機能など、システム管理者向けに予約されたプログラムがが 含まれます。

/usr/local

システム管理者が、ディストリビューションに依存しない拡張を インストールするためのディレクトリです。

/usr/share/doc

お使いのシステムに対する様々な文書ファイルやリリースノートを 配置するディレクトリです。 manual サブディレクトリ には、このマニュアルのオンライン版が含まれています。また、お使いの システムに複数の言語をインストールしている環境では、このディレクトリに 異なる言語向けの各種マニュアルが含まれています。

また、 packages サブディレクトリには、お使いの システムにインストールされている各種ソフトウエアパッケージの文書が 含まれています。パッケージごとに、下記のようなサブディレクトリが 作成されています: /usr/share/doc/packages/パッケージ名 これらのディレクトリには、パッケージの README ファイルやいくつかのサンプル、 設定ファイルや追加のスクリプトなどが含まれています。

なお、 HOWTO をお使いのシステムにインストールしている場合は、 /usr/share/doc ディレクトリには howto サブディレクトリが存在し、 Linux ソフトウエアでの設定方法や操作方法に 関連した追加の文書が含まれています。

/var

/usr には静的で読み込み専用のデータが保存されている のに比べ、 /var にはシステムが動作している際に 随時書き込まれるファイルが含まれています。たとえばログファイルや スプール (一時保管) データなどが該当します。 /var/log/ ディレクトリにある最も重要なログファイルについて、詳しくは 表A.2「ログファイル」 をお読みください。

/windows

お使いのシステムに Microsoft Windows と Linux の両方がインストール されている場合にのみ利用可能なディレクトリです。お使いのシステム内の Windows パーティション上にある全てのデータが含まれます。この ディレクトリ内に対して書き込みができるかどうかは、 Windows 側で使用している ファイルシステムの種類に依存します。 FAT32 をお使いの場合は、この ディレクトリ内のファイルは自由に読み書きすることができます。 NTFS の場合でも openSUSE には書き込みサポートが付属しているため、 読み込み/書き込みを行なうことができますが、使用しているドライバ NTFS-3g ファイルシステムの仕様により、いくつかの制限があります。 詳しくは 項 「同一のコンピュータにおける異なる OS 上のファイルへのアクセス」 (第27章 ファイルのコピーと共有, ↑リファレンス) をお読みください。.

18.2. シェルスクリプトの作成

シェルスクリプトは、様々な種類の処理を行なうのに便利な方法です: データの収集やテキストファイル内の単語またはフレーズの検索など、多くのことを 便利に行なうことができます。下記の例では、テキストを出力するための 小さなシェルスクリプトを示しています:

例18.1 テキストを出力するシェルスクリプト

#!/bin/sh 1
# Output the following line: 2
echo "Hello World" 3

1

最初の行は シェバン と呼ばれるもので始まっています。 この文字列 (#!) は、このファイルがスクリプトである ことを宣言する識別子になっています。スクリプトはシェバンに続いて指定された インタプリタで実行されます。この場合は /bin/sh を 実行します。

2

2 行目はハッシュ記号で始まる行で、これはコメント行を表わしています。 それが何をするのかわかりにくいような場合に、コメントを記載しておくのが よいでしょう。

3

3 行目は内蔵コマンド echo を実行し、テキストを表示 しています。


なお、スクリプトを実行する前に下記の要件を満たす必要があります:

  1. 各スクリプトにはシェバンの書かれた行が含まれていなければなりません (上記の例では既に含まれています) 。スクリプトにその行が存在しない場合は、 インタプリタを手動で呼び出さなければなりません。

  2. スクリプトは自由な場所に配置することができますが、シェルから発見可能な ディレクトリに配置しておくことをお勧めします。シェルがスクリプト を発見するための処理は、環境変数 PATH にある情報から行ないます。 通常は一般ユーザが /usr/bin などに書き込むことはできない ので、作成したスクリプトは ~/bin/ ディレクトリに保存する のがお勧めです。上記の例では、 hello.sh のようなファイル名に なっています。

  3. スクリプトには実行パーミッションが付けられていなければなりません。下記の コマンドを実行すると実行パーミッションを設定することができます:

    chmod +x ~/bin/hello.sh

上記の要件を全て満たすことができたら、下記の方法でスクリプトを実行することが できます:

  1. 絶対パスを指定した実行.  絶対パスを指定することでスクリプトを実行します。この例の場合、 ~/bin/hello.sh のように入力します。

  2. 任意の場所からの実行.  PATH 環境変数内にスクリプトを保存しているディレクトリが 含まれる場合、単に hello.sh と入力することで実行する ことができます。

18.3. コマンドイベントのリダイレクト

各コマンドには 3 種類の入出力チャンネルが存在します:

  • 標準出力.  これが既定の出力チャンネルです。コマンドが何らかの出力を行なった 場合、標準出力チャンネルを利用して出力されます。

  • 標準入力.  コマンドがユーザまたは他のコマンドからの入力を必要とした場合、 このチャンネルを通じて読み込みます。

  • 標準エラー.  コマンドはエラー報告用にこのチャンネルを使用します。

これらのチャンネルを他の箇所に転送 (リダイレクト) するには、下記のような方法があります:

コマンド > ファイル

コマンドの出力データを指定したファイルに保存します。既存のファイルがあれば、 そのファイルは上書きされます。たとえば ls コマンドの 出力を listing.txt ファイルに出力したい場合は、 下記のようになります:

ls > listing.txt
コマンド >> ファイル

コマンドの出力データを指定したファイルに追記します。たとえば ls コマンドの出力を listing.txt ファイルに追記したい場合は、下記のようになります:

ls >> listing.txt
コマンド < ファイル

指定したコマンドの入力データとしてファイルを指定します。たとえば read コマンドを利用してファイルの内容を変数 a に代入したい場合は、下記のようになります:

read a < foo
コマンド1 | コマンド2

左側のコマンドの出力を右側のコマンドの入力として利用するよう指定します。 たとえば cat コマンドを利用して /proc/cpuinfo ファイルの内容を出力し、その出力に 対して grep コマンドを適用し、 cpu を含む行だけを取り出したい場合は、下記のようになります:

cat /proc/cpuinfo | grep cpu

また、各チャンネルには ファイル記述子 が割り当てられて います: 0 (ゼロ) が標準入力、 1 が標準出力、 2 が標準エラーです。 <> 文字には、その前に ファイル記述子を指定することができるため、たとえば下記の例では foo で始まるファイルを検索しますが、標準エラー 出力は /dev/null に転送することで省略しています:

find / -name "foo*" 2>/dev/null

18.4. 別名定義の使用

別名とは 1 つまたは複数のコマンドを短縮して定義するものです。別名の書式は 下記のとおりです:

alias 名前=定義

たとえば下記の例では lt という別名に対して、長い形式の 出力 (-l オプション) と更新日次による並べ替え (-t) 、および並べ替えを逆順で行なう設定 (-r) をそれぞれ指定しています:

alias lt='ls -ltr'

全ての別名定義を表示するには、 alias コマンドを使用します。 また、別名定義を削除するには unalias で別名を指定することで 行なうことができます。

18.5. Bash 内での変数の使用

シェルでの変数はグローバルにもローカルにもすることができます。グローバル変数 は環境変数とも呼ばれるもので、全てのシェル内でアクセスすることができます。 逆にローカル変数は現在のシェル内でしか見えないものになります。

全ての環境変数を表示するには、 printenv コマンドを使用します。 変数の値を表示するには、パラメータとして変数名を指定します:

printenv PATH

グローバルまたはローカルの変数を表示するには、 echo コマンド を使用して参照することもできます:

echo $PATH

ローカル変数を設定するには、変数名の後ろにイコール記号を付け、その後ろに 値を書きます:

PROJECT="SLED"

イコール記号の前後にはスペースを入れないでください。スペースを入れると エラーになってしまいます。環境変数を設定するには、 export コマンドを使用します:

export NAME="tux"

変数を削除するには、 unset コマンドを使用します:

unset NAME

お使いのシェルスクリプト内で利用できる、一般的な環境変数の一覧を示します:

表18.5 便利な環境変数

HOME

現在のユーザのホームディレクトリ

HOST

現在のホスト名

LANG

ツールがローカライズ (各国語対応) されている場合、この環境変数の値を 読み込んで言語を判断します。英語の場合は、値に C を指定することもできます。

PATH

シェルの検索パスを示します。ディレクトリの一覧をコロン区切りで 指定します。

PS1

各コマンド入力の前に表示される、通常のプロンプトを指定します。

PS2

複数行のコマンドを実行する際に表示する、 2 行目以降のプロンプトを 指定します。

PWD

現在の作業ディレクトリを表わします。

USER

現在のユーザを表わします。


18.5.1. パラメータの使用

たとえば、 foo.sh というスクリプトが存在している 場合、下記のように実行することができます:

foo.sh "Tux Penguin" 2000 

お使いのスクリプトに対して渡された全てのパラメータにアクセスするには、 位置パラメータを利用します。最初のパラメータが $1 、 2 番目が $2 などのようになっています。最大で 9 つまでの パラメータを取得することができます。スクリプト名を取得したい場合は、 $0 をお使いください。

下記の foo.sh スクリプトでは、 1 番目から 4 番目まで に指定したパラメータを全て表示します:

#!/bin/sh
echo \"$1\" \"$2\" \"$3\" \"$4\"

上記の例のように実行した場合は、下記のように出力されます:

"Tux Penguin" "2000" "" ""

18.5.2. 変数置換の使用

変数置換は、変数の中身について左から右にパターンを適用するための 仕組みです。下記のような書式があります:

${VAR#pattern}

左から順に読み出し、最も短い適合パターンを取り除きます:

file=/home/tux/book/book.tar.bz2
echo ${file#*/}
home/tux/book/book.tar.bz2
${VAR##pattern}

左から順に読み出し、最も長い適合パターンを取り除きます:

file=/home/tux/book/book.tar.bz2
echo ${file##*/}
book.tar.bz2
${VAR%pattern}

右から順に読み出し、最も短い適合パターンを取り除きます:

file=/home/tux/book/book.tar.bz2
echo ${file%.*}
/home/tux/book/book.tar
${VAR%%pattern}

右から順に読み出し、最も長い適合パターンを取り除きます:

file=/home/tux/book/book.tar.bz2
echo ${file%%.*}
/home/tux/book/book
${VAR/pattern_1/pattern_2}

VAR で示される変数の内容について、 pattern_1pattern_2 で置き換えます:

file=/home/tux/book/book.tar.bz2
echo ${file/tux/wilber}
/home/wilber/book/book.tar.bz2

18.6. コマンドのグループ化と組み合わせ

シェルでは条件付きの実行を行なうため、コマンドをつなぎ合わせたりグループ化 したりすることができます。それぞれのコマンドの終了コードでその処理が 成功したか失敗したかを判断します。 0 (ゼロ) が返された場合、コマンドは成功した ものと見なされ、それ以外の場合はコマンド固有のエラーになったものと 判断されます。

下記の一覧では、どのようにコマンドをグループ化するかについて説明しています:

Command1 ; Command2

コマンドを順々に実行します。終了コードはチェックしません。 たとえば下記の例では、 cat コマンドでファイルの 内容を表示し、 ls コマンドでそのファイルの属性情報を 表示します。終了コードとは無関係に実行されます:

cat filelist.txt ; ls -l filelist.txt
Command1 && Command2

左側のコマンドが成功した場合にのみ右側のコマンドを実行します (論理積) 。 たとえば下記の例では、ファイルの中身を表示したあと、その処理が成功した 場合にのみファイルの属性情報を表示します (前の項目とは処理が異なっている ことに着目してください):

cat filelist.txt && ls -l filelist.txt
Command1 || Command2

左図輪のコマンドが失敗した場合にのみ右側のコマンドを実行します (論理和) 。 たとえば下記の例では、 /home/tux/foo ディレクトリの 作成が失敗した場合にのみ /home/wilber/bar ディレクトリ を作成します:

mkdir /home/tux/foo || mkdir /home/wilber/bar
funcname(){ ... }

シェル関数を作成します。位置パラメータを利用することで関数のパラメータに アクセスすることができます。下記の例では、短いメッセージを表示する hello という関数を定義しています:

hello() { echo "Hello $1"; }

関数は下記のようにして呼び出すことができます:

hello Tux

上記を実行すると、下記のように表示されます:

Hello Tux

18.7. 一般的なフロー制御

お使いのスクリプトについてフロー制御を行なうには、シェルに用意されている while, if, for, case の各コマンドを利用して組み立ててください。

18.7.1. if 制御コマンド

if コマンドは条件分岐を行なうコマンドです。 たとえば下記の例では、現在のユーザが Tux であるかどうかを確認しています:

if test $USER = "tux"; then
  echo "Hello Tux."
else
  echo "You are not Tux."
fi

条件表現は複雑にも単純にもすることができます。下記の例では、 foo.txt ファイルが存在するかどうかを判断しています:

if test -e /tmp/foo.txt ; then
  echo "Found foo.txt"
fi

test 表現は角括弧を利用して省略することもできます:

if [ -e /tmp/foo.txt ] ; then
  echo "Found foo.txt"
fi

便利な条件表現について、詳しくは http://www.cyberciti.biz/nixcraft/linux/docs/uniqlinuxfeatures/lsst/ch03sec02.html. (英語) をお読みください。

18.7.2. コマンドの繰り返し処理の作成

for ループは、項目の一覧にあるものそれぞれに対して コマンドを実行するための仕組みです。たとえば下記の例では、現在のディレクトリ 内にあるそれぞれの PNG ファイルについて、いくつかの情報を表示することが できます:

for i in *.png; do
 do
 ls -l $i
done

18.8. さらなる情報

Bash について重要な情報は、マニュアルページ man bash で 提供されています。特定のトピックについての詳細は、それぞれ下記をお読み ください (それぞれ英語です):


openSUSE スタートアップ 13.1