シェルスクリプトとは
シェルスクリプトとはコマンドやシェルの組み込みコマンドなどをファイルに記述し、実行できるようにしたものである。
またプログラムの制御構造なども使用でき、柔軟な処理が可能であり、/etc/rc.d/initd/ディレクトリ内の起動スクリプトなどはシェルスクリプトである。

シェルスクリプトを実行するには実行権限および読み込み権限が必要です。
またシェルスクリプトファイルの1行目にはシェルスクリプトを実行するシェルのパスを記述します。
シェル変数
スクリプトファイル内でも、シェル変数を定義することができる。またその変数を参照する場合は変数名の前に" $ "を
付けることで参照できる。変数名に使用できる文字は英数字および" _ "(アンダーバー)であり先頭は英字を使用しなくてはならない。

シェル変数
変数名="値"

この変数名と値の間の" = "の前後にスペースを入れてはならない。
同一の値が複数ある場合は1つの変数を定義した方が修正も1箇所で済むので効率がよい。
特殊なシェル変数
シェルスクリプトは引数を利用することができ、bashに初めから用意された特殊な変数を使用し参照することができる。
これらの変数は参照するもので、値を代入することはできない。

特殊な変数
変数説明
$n nは数字であり、$0はシェルスクリプト名、以降$1、$2…は第1引数、第2引数…である。第10引数以降は${10}、${11}…で参照する。
$# 与えられた引数の個数
$@ $0以外の全ての引数("$@"のようにダブルクォーテーションで囲んだ場合"$1" "$2" …"のように個別に展開される。)
$* $0以外の全ての引数("$@"のようにダブルクォーテーションで囲んだ場合"$1 $2 …"のように展開される。)
$? 最後に実行したコマンドの終了ステータス
$! 最後に実行したバックグラウンドコマンドのPID
$$ シェルのPID
$- 現在のオプションフラグ

次のシェルスクリプトを実行します。
#cat script
#!/bin/sh

echo $#
echo $0 $1 $2 $3
echo $@
echo $*
echo $?
echo $!
echo $$
echo $-
結果は以下のようになります。
$./script red green blue
2
./script red green blue
red green blue
red green blue
0
19230
22478
hB
算術演算子
シェルスクリプトでは算術演算にexprコマンドを使用します。C言語のような「hoge = 10 + 8」のような書き方はできません。
exprコマンドで使用できる演算子は以下の通りです。

数値演算
算術演算子説明
num1 + num2 num1とnum2の和
num1 - num2 num1とnum2の差
num1 * num2 num1とnum2の積
num1 / num2 num1とnum2の商
num1 % num2 num1とnum2の剰余

関係演算
num1 & num2 num1及びnum2が共に0またはNULL以外ならnum1を返す。それ以外は0を返す。
num1 | num2 num1が0またはNULL以外ならnum1を返す。0ならnum2を返す。
num1 = num2 num1とnum2が一致なら1を返す。それ以外は0を返す。
num1 > num2 num1がnum2より大きいなら1を返す。それ以外は0を返す。
num1 < num2 num1がnum2未満なら1を返す。それ以外は0を返す。
num1 >= num2 num1がnum2以上なら1を返す。それ以外は0を返す。
num1 <= num2 num1がnum2以下なら1を返す。それ以外は0を返す。
num1 != num2 num1とnum2が不一致なら1を返す。それ以外は0を返す。

文字列演算
文字列 : 正規表現 文字列と正規表現が一致し、正規表現に"\(" と "\)"が使われていればマッチした文字列を返す。そうでないなら マッチした文字列の長さを返す。また、一致しなかった場合"\(" と "\)"が使われていればNULLを返し、そうでないなら 0を返す。
index 文字列1 文字列2 文字列1から文字列2のいずれかの文字が最初に見つかった位置を返す。見つからなければ0を返す。
length 文字列 文字列の長さを返す。
match 文字列 正規表現 "文字列 : 正規表現"と同じ。
quote 文字列 文字列に演算子やキーワードを含んでも通常の文字列として扱う。
substr 文字列 文字位置 文字列長 文字列の部分文字列を返す。部分文字列は文字位置から始まり、文字列長の長さである。文字位置や文字列長が正の数値でない場合は NULLを返す。

次のシェルスクリプトを実行します。
#cat script2
#!/bin/sh

var1=100
var2=0
num1=`expr 10 + 30`
num2=`expr $var1 - 30`
num3=`expr 100 % 30`
num4=`expr $var2 && 1000`
echo $num1 $num2 $num3 $num4
結果は以下のようになります。
$./script2
40 70 10 0
コメント
シェルスクリプト内にコメントを挿入することができます。コメント部分の行頭に" # "(シャープ)を付けることで、
コメントと解釈されます。
条件分岐(if)
ある条件によって行わせる処理が異なる場合に条件分岐(if文)を使用します。条件が不成立の時に実行するelseは省略することもできます。

構文
if 条件
then
	条件が成立した時に実行するコマンド
else
	条件が不成立の時に実行するコマンド
fi
またif文の条件にtestコマンドを使用することで条件の真偽を判定することができる(ファイルのチェック等)。条件が真(成立)の時は0を返し、偽(不成立)の時は1を返します。

構文
if [ 条件 ]; または if test 条件
then
	条件が成立した時に実行するコマンド
else
	条件が不成立の時に実行するコマンド
fi

条件を" [ ] "で囲む場合は" [ "及び" ] "の前後に半角スペースを入れる必要があることに注意してください。
(最後に" ; "を付けた場合は最後の半角スペースは必要ありません。) testコマンドのオプションは以下の通りです。

ファイル形式のチェック
-b ファイル名 指定したファイルがブロックデバイスファイルなら真である。
-c ファイル名 指定したファイルがキャラクタデバイスファイルなら真である。
-d ファイル名 指定したファイルがディレクトリなら真である。
-f ファイル名 指定したファイルが通常ファイルなら真である。
-L ファイル名 指定したファイルがシンボリックリンクなら真である。
-p ファイル名 指定したファイルが名前付きパイプなら真である。
-S ファイル名 指定したファイルがソケットなら真である。

ファイルパーミッションのチェック
-g ファイル名 指定したファイルにSGIDがセットされていれば真である。
-k ファイル名 指定したファイルにスティッキービットがセットされていれば真である。
-r ファイル名 指定したファイルが読み取り可能なら真である。
-u ファイル名 指定したファイルにSUIDがセットされていれば真である。
-w ファイル名 指定したファイルが書き込み可能なら真である。
-x ファイル名 指定したファイルが実行可能なら真である。

その他のファイルのチェック
-e ファイル名 指定したファイルが存在すれば真である。
-s ファイル名 指定したファイルのファイルサイズが0より大きければ真である。

文字列のチェック
-n 文字列 文字列の長さが0より大きければ真である。
-z 文字列 文字列の長さが0であれば真である。
文字列1 = 文字列2 2つの文字列が等しければ真である。
文字列1 != 文字列2 2つの文字列が等しくなければ真である。

数値のチェック
数値1 -eq 数値2 2つの数値が等しければ真である。
数値1 -ge 数値2 数値1が数値2以上であれば真である。
数値1 -gt 数値2 数値1が数値2より大きいのであれば真である。
数値1 -le 数値2 数値1が数値2以下であれば真である。
数値1 -lt 数値2 数値1が数値2未満であれば真である。
数値1 -ne 数値2 2つの数値が等しくなければ真である。

論理結合
!条件 条件が偽であれば真である。
条件1 -a 条件2 条件1と条件2の両方が真であれば真である。
条件1 -o 条件2 条件1と条件2のどちらかが真であれば真である。

/home/hoge/tmpがディレクトリであるかチェックします。
$test -d /home/hoge/tmp
$echo $? ←直前のコマンドの終了ステータス
0 ←/home/hoge/tmpはディレクトリである(真)
以下のシェルスクリプト(edit)を実行します。このシェルスクリプトは引数が通常ファイルならviでそのファイルを開き、
ファイルが存在しないまたは通常ファイルでない場合はエラーを表示します。
$cat edit
#!/bin/sh

if [ -f "$1" ];
then
	vi $1
else
	echo "Error $1"
fi
textは通常ファイルなのでviで表示します。

$./edit text
hoge
hoge
~
~
~
~
~
"text" 2L, 8C
directoryはディレクトリなのでエラーを表示します。
$./edit directory
Error text2
条件分岐(case)
変数の値によって行わせる処理が異なる場合に条件分岐(case文)を使用します。C言語とは違いパターンに一致した時点で外に出ます。
どのパターンとも一致しなかった場合は何も行いません。またパターンを" | "で区切って論理和(or)をとることができます。

構文
case 変数 in
	パターン1)
		パターン1と一致した時に実行するコマンド
		;;
	パターン2)
		パターン2と一致した時に実行するコマンド
		;;
	パターンn)
		パターン2と一致した時に実行するコマンド
		;;
esac
以下のシェルスクリプト(edit)を実行します。このシェルスクリプトは拡張子がtxt、doc、datのファイルはviで開き
それ以外のファイルはlessで表示します。
$cat edit
#!/bin/sh

case $1 in
        *.txt | *.doc | *.dat)
                vi $1
                ;;
        *)
                less $1
                ;;
esac
hoge.txtは拡張子がtxtなのでviで表示します。
$./edit hoge.txt
hoge
hoge
~
~
~
~
~
"text" 2L, 8C
linuxfileの拡張子はtxt、doc、datのいずれでもないのでlessで表示します。
$./edit linuxfile
turbolinux
redhatlinux
text (END)
ループ処理(for)
与えられた引数の数だけ処理の繰り返しを行いたい場合はfor文を使用します。for文はinの後に続く引数を変数に代入しながら doとdoneの間に記述されたコマンドを繰り返し実行します。そしてinの後の引数がなくなり次第ループから抜けます。引数には"$@"や"$*"を 使用することも可能です。

構文
for 変数 in 引数…
do
	繰り返し実行されるコマンド
done
以下のシェルスクリプト(for)を実行します。
$cat for
#!/bin/sh

for a in redhat turbo vine
do
	echo "$a"
done
以下のように表示されます。
$./for
redhat
turbo
vine
次に全ての引数を表す$@を引数に指定したシュルスクリプトを実行します。
$cat for
#!/bin/sh

for a in "$@"
do
	echo "$a"
done
以下のように表示されます。
$./for redhat turbo vine
redhat
turbo
vine
また"in 引数"を省略した場合も"$@"を引数に指定した場合と同じ結果が得られます。
ループ処理(while)
ある条件が真である間処理を繰り返したい場合はwhile文を使用します。while文は条件の終了状態が真である場合は doとdoneの間に記述されたコマンドを実行します。
そして条件の終了状態が偽になり次第ループから抜けます。

構文
while 条件 
do 
	繰り返し実行されるコマンド	
done 
以下のシェルスクリプト(while)を実行します。これは1から5までカウントしています。
$cat while
#!/bin/sh

count=1
while [ $count -le 5 ];
do
	echo "$count"
	count=`expr $count + 1`
done
以下のように表示されます。
$./while
1
2
3
4
5
ループ処理(until)
ある条件が偽である間処理を繰り返したい場合はuntil文を使用します。until文は条件の終了状態が偽である場合は doとdoneの間に記述されたコマンドを実行します。
そして条件の終了状態が真になり次第ループから抜けます。

構文
until 条件 
do 
	繰り返し実行されるコマンド	
done 
以下のシェルスクリプト(until)を実行します。これは5から1までカウントダウンしています。
$cat until
#!/bin/sh

count=5
until [ $count -eq 0 ];
do
	echo "$count"
	count=`expr $count - 1`
done
以下のように表示されます。
$./while
5
4
3
2
1
ループ制御(break)
for, while, untilなどのループから途中で抜けたい場合はbreak文を使用します。抜けたいループの深さを指定することもできます。 指定された深さがループの深さを超えた場合は全てのループから抜けます。また深さを省略した場合は深さは1になります。

構文
break 抜けたいループの深さ

以下のようにfor文が3つのネストになっている場合3を指定すると全てのループから抜けます。
$cat break
#!/bin/sh

for a
do
	for b
	do
		for c
		do
			break 3			
		done
	done
done
ループ制御(continue)
for, while, untilなどのループの途中でそれ以降の処理をスキップしたい場合はcontinue文を使用します。continue文はループを抜けるわけではなく continue文以降の処理をスキップしループの先頭に戻り次の繰り返し分からループの実行を継続します。break文同様処理をスキップし先頭に戻したいループの深さを 指定することができます。指定された深さがループの深さを超えた場合は一番外のループの先頭に戻りループを継続します。 また深さを省略した場合は深さは1になります。

構文
continue 実行を継続したいループまでの深さ

以下のようにfor文が3つのネストになっている場合2を指定すると"for a"のループから実行を継続します。
$cat continue
#!/bin/sh

for a
do
	for b
	do
		for c
		do
			if [ $c = redhat ];
			then
				continue 2
			fi
		done
	done
done
シェル関数
シェルスクリプトでも関数を作成することができます。関数は他のプログラムなどから呼び出される共通処理の記述された プログラムの部品です。関数をシェルに登録することで関数をコマンドのように使用することが可能となります。 またfunctionは省略することができます。

構文
[ function ] 関数名 () {
	コマンド
}
ここで文字列を表示する関数printを作成します。
$cat print
print () {
	echo "$1"
}
このファイルをsourceコマンドまたは.コマンドで実行します。

$. print

そしてprint関数を呼び出します。(コマンドを実行することと同様)
$print 'shellscript'
shellscript
しかしシェルスクリプトはシェルから起動される別プロセスであるサブシェル上で実行されるためこのままでは 毎回シェルごとに関数を登録することになるので、親シェルの関数をサブシェルに継承させます。これにはexport コマンドを使用します。
$export -f print
以上でこのシェルから実行されるシェルスクリプトでもprint関数を呼び出すことができます。

また関数を削除するにはunsetコマンドを使用します。
関数を確認するにはdeclareやtypesetコマンドを使用し、-fオプションは関数名や関数の定義を表示し、-Fオプションは 関数名のみ表示します。