topページ / Shell Script

Shell Scriptをやってみようか(仮題)

Shell ScriptはLinuxやUNIXで使用される簡単で強力なスクリプト言語である。このページではその書き方などについて説明する。

用意するもの

0 viエディタの使い方

0.1 起動と終了

以下のコマンドで起動する。

$ vi

ファイル名を指定した場合はファイルを開く。

viは起動した直後、文字の挿入ができないモードとなっている。これをコマンドモードという。終了するときは、コマンドモードで「:q」とタイプし、Enterを押す。ファイルを編集して、セーブせずに終了したい場合は「:q!」とする。

0.2 カーソルの移動

カーソルキーが使える場合もあるが、基本はアルファベットキーによる移動である。

なお、このキー操作に慣れておけば、nethackというゲームで遊ぶときも、キャラクタ移動にそれほど困らないはずである(あちらは斜め移動もあるが・・・)。

0.3 挿入モードとコマンドモードの切り替え

タイプした文字がそのまま挿入できるモードを挿入モードという。vi起動時はコマンドモードであるため、ファイルの編集をするには挿入モードにしなければならない。

コマンドモードから挿入モードへの切り替えはいくらか方法があるが、ここでは代表的なものを紹介する。

要は、vi起動後、iキーを押せば挿入モードになるのである。

また、挿入モードからコマンドモードに切り替えるときはESCキーを押す。

0.4 文字を消す

DelキーやBSキーが使えることもあるが、コマンドモードでxキーを押して消すのが基本である。viでは文字の挿入以外はほとんどの機能をコマンドモードでこなすことになる。

また、コマンドモードでddとタイプするとその行が消去される。

0.5 アンドゥとリドゥ

アンドゥはコマンドモードでuをタイプする。リドゥは「:redo」とタイプしてエンターを押すか、[Ctrl]-rをタイプする。

0.6 コピー/カットとペースト

コマンドモードで以下のコマンドをタイプする。

0.7 ファイルの保存

コマンドモードで「:w」とタイプし、エンターを押す。別名で保存する場合や新規作成の場合は「:w [ファイル名]」とファイル名を指定する。

0.8 検索

コマンドモードで以下のコマンドをタイプする。

なお、検索ワードを省略した場合は前回の検索ワードで検索する。

0.9 ウインドウ分割

コマンドモードで「:split」または「:vsplit」とタイプし、エンターキーを押す。splitは上下に分割、vsplitは左右に分割する。

また、「:split [ファイル名]」、「:vsplit [ファイル名]」とファイル名を指定すると、指定したファイルを分割したウインドウで開く。

ウインドウ間の移動は、[Ctrl]+w [Ctrl]+w、又は[Ctrl]+w 方向で移動できる。

分割したウインドウを閉じるときは「:q」、「:q!」コマンドを使う。

0.10 キーボードマクロ

コマンドモードでqキーを押した後、適当なキーを押すと、マクロの記録が始まる。

もう一度コマンドモードでqを押して記録を終了するまでの動作が記録される。

コマンドモードで@キーを押した後、記録したときに押したキーを押すと、記録した動作が実行される。

... こんなもんでいいかな?

1 Linuxコマンドの使い方の確認

そこそこ集まっているコマンドのページはこちら

1.1 リダイレクト

コマンドの入力、出力を<、>で制御できる。

ディレクトリの中身をファイルに出力するには次のようにする。

$ ls > [ファイル名]

ファイルの中身をcatするには、

$ cat < [ファイル名]

とする。catは第一引数の中身を表示するので、この場合「cat [ファイル名]」としても同じ結果になる。なお、逆の

$ [ファイル名] > cat

とすると、エラーになる。[ファイル名]はコマンドではないので当然だが。

なお、「>>」で、ファイルの最後に追加することができる。

1.2 パイプライン

コマンドの実行結果を別のコマンドに渡すにはパイプライン「|」を使用する。

次のコマンドは一画面で表示し切れないps auxの実行結果をlessに渡して、確認できるようにしたもの。

$ ps aux | less

rootが含まれるもののみを表示するために、grepコマンドをはさむと、次のようになる。

$ ps aux | grep root | less

2 はじめてのシェルスクリプト

2.1 Hello World

エディタでファイルを作成し、次のように入力する。

#!/bin/bash
echo Hello World

#!/bin/bashは「bashを使うぞ」という宣言。

echoは続く文字列を表示するコマンド。

ファイルの実行権限を変更して実行する。

$ chmod 700 [ファイル名]
$ ./[ファイル名]
Hello World

Hello Worldと表示されたら成功。

2.2 環境変数の表示

envコマンドで確認できる環境変数を使用するには$[環境変数]とすればよい。

#!/bin/bash
echo Home=$HOME

このスクリプトでは自分のホームディレクトリが、「Home=ホームディレクトリ」のように表示される。

2.3 引数

$[番号]で、引数が取得できる。$0はコマンド自体、$1から、コマンドに続く引数が取得できる。

#!/bin/bash
echo ---$1の中身---
ls $1

スクリプトに続けてディレクトリを指定すると、ディレクトリの中身を表示するスクリプト。

引数の数を調べるには、$#とする。引数がない場合、$#は0となる。

2.4 条件分岐

if ~ fiで条件分岐ができる。

if [ 条件 ]
then
	[条件を満たしたときの処理]
fi

インデントは見やすくするためにつけているだけであり、無くてもOK。

条件の指定の仕方は以下の通り

次のスクリプトでは、引数が1つ以上あれば、第一引数の値を表示する。

#!/bin/bash
if [ $# -ge 1 ]
then
	echo $1
fi

括弧と条件の間の空白は必要。無いとエラーになる。

文字列比較の場合は以下の条件を指定する。aとbは比較対象文字列。

次のスクリプトは、第一引数が「abc」であればそれを表示する。

#!/bin/bash
if [ $# -ge 1 ]
then
	if [ $1 = "abc" ]
	then
		echo $1
	fi
fi

また、ファイルに対する判定も行うことができる。

次のスクリプトは、ファイル名を指定し、それが存在したら表示する。

#!/bin/bash
if [ $# -ge 1 ]
then
	if [ -s $1 ]
	then
		echo $1
	fi
fi

ディレクトリかどうかをチェックするには次のようにする。

#!/bin/bash
if [ $# -ge 1 ]
then
	if [ -d $1 ]
	then
		echo $1
	fi
fi

条件を満たさなかった場合の処理はelseで書くことができる。

if [ 条件 ]
then
	[条件を満たしたときの処理]
else
	[条件を満たさなかったときの処理]
fi

次のスクリプトはファイルであれば「file: [ファイル名]」を、ディレクトリであれば「dir: [ファイル名]」を表示する。

#!/bin/bash
if [ $# -ge 1 ]
then
	if [ -f $1 ]
	then
		echo file: $1
	else
		if [-d $1 ]
		then
			echo dir: $1
		fi
	fi
fi

elseの場合に再度条件分岐をするには上の方法でもよいが、elifを使うことができる。

if [ 条件1 ]
then
	[条件1を満たしたときの処理]
elif [ 条件2 ]
	[条件2を満たしたときの処理]

# .... 省略

fi

上のスクリプトを書き直すとつぎのようになる。

#!/bin/bash
if [ $# -ge 1 ]
then
	if [ -f $1 ]
	then
		echo file: $1
	elif [ -d $1 ]
	then
		echo dir: $1
	fi
fi

なお、条件式を複数つなげる必要がある場合はcase~esacが使用できる。

case $[変数] in
	[パターン]) [パターンに一致したら実行する処理]
	           [パターンに一致したら実行する処理]
	           .........
	           [パターンに一致したら実行する処理];;

	[パターン]) [パターンに一致したら実行する処理]
	           [パターンに一致したら実行する処理]
	           .........
	           [パターンに一致したら実行する処理];;

# .... 省略

esac

パターンには数字や文字列が指定できる。-fなどを指定してファイルの存在チェックなどはできない。

パターンに*を指定したら上記どれにも一致しなかったときの処理を設定する。(C言語でいうdefault:の役割。)

以下、使用してみた例。2つのパターンを用意しておき(パターン1=abc、パターン2=def)、引数がパターンに一致したら「pattern1」などというように表示した後に引数を表示するスクリプト。一致しなかったら「default」と表示される。

#!/bin/bash
if [ $# -ge 1 ]
then
	case $1 in
		"abc") echo pattern1
		echo $1;;
		"def") echo pattern2
		echo $1;;
		*) echo default
		echo $1;;
	esac
fi

2.5 変数

変数は次のように定義して、使用する。

#!/bin/bash

a=1
echo $a
a=`expr $a + 5`
echo $a
a=`expr $a \* 5`
echo $a

aが変数。代入以外では$aとする。exprは計算結果を返す。掛け算はワイルドカードと区別するために\*とする。また、exprを囲んでいるのは「'」ではなく、「`」であることに注意。

コマンドの実行結果を返すときは「`」で囲む。

lsの結果をaに格納し、表示する例

#!/bin/bash

a=`ls`
echo $a

2.6 ループ

ループはforループとwhileループが使える。

for (( [初期条件] ; [繰り返し条件] ; [ループ時処理 ))
do
	[処理]
done
while [ 繰り返し条件 ]
do
	[処理]
done

forループの繰り返し条件は「==」や「<」などの記号を使うのに対し、whileでは「-eq」や「-lt」をつかうのに注意。

次のスクリプトはともに1から9までを表示する。

#!/bin/bash

for (( a = 1; a < 10; a++ ))
do
	echo $a
done
#!/bin/bash

a=1
while [ $a -lt 10 ]
do
	echo $a
	a=`expr $a + 1`
done

forではセットする値リストを使うこともできる。リストの値が一つ一つ変数にセットされ、処理が行われる。

for [変数] in [値リスト]
do
	[処理]
done

以下、2,4,6,8,99,AAを表示するスクリプト

#!/bin/bash

for a in 2 4 6 8 99 "AA"
do
	echo $a
done

カレントディレクトリの全ファイルを調べ、ファイルであれば「file: [ファイル名]」を、ディレクトリであれば「dir : [ファイル名]」を表示するスクリプト。

#!/bin/bash

b=`ls`
for a in $b
do
	if [ -f $a ]
	then
		echo file: $a
	elif [ -d $a ]
	then
		echo dir : $a
	fi
done