LinuC Level1 v10.0 対策コース(パート2)3/29
シェルスクリプトの作成・基本文法について
こちらの記事ではシェルスクリプトの作成について解説します。
シェルスクリプトとは
シェルスクリプトは、シェル上で実行する一連のコマンドや制御文などを組み合わせたプログラムです。頻繁に利用するコマンドや条件によって処理を変えたい時などは、シェルススクリプトを作成すると、自動で実行できるようになります。シェルによって文法は異なりますが、多くの場合繰り返し(for/while)や条件分岐(if/case)などの制御文、変数や配列、関数などが備わっています。データ型や高度な算術演算などは備わっていないため、複雑なプログラミングには適していません。本記事では様々なコマンドを組み合わせて処理を行い、作業の効率を上げる目的で解説をします。
bashシェルスクリプトの作成
bashでシェルスクリプトを作成するための基本的な文法を解説します。
シバン(shebang)
シバン(shebang)とは、既知のバイナリ形式ではないファイルを実行した際にインタプリタを指定できる仕組みです。シェルスクリプトの場合先頭に「#!
」と記述し、続けてスクリプトを実行するシェルのパスを記述します。例えばbashでシェルスクリプトを実行する場合は#!/bin/bash
と記述することで、スクリプトはbashシェルで実行されます。
関数
関数は一連の処理をまとめたものです。関数に頻繁に使用するコマンドの組み合わせを定義すると、その都度コマンドを入力しなくても、関数を呼び出すだけで実行でき便利です。bashで関数を定義するにはbashのビルトインコマンドであるfunction
コマンドを使用します。
<関数の書式>
一般的にコマンドラインで関数を定義する際は、以下のように記述します。
function 関数名() { 複合コマンド; } #リダイレクトを記述することができる
#functionが使用されるときは、()が省略可能
なお、function
は省略して記述することができます。
関数名() { コマンド; }
シェルスクリプト内で記述する時は、以下のように記述します。
#!/bin/bash
function 関数名()
{
コマンド
}
こちらもfunction
を省略して記述することができます。
#!/bin/bash
関数名()
{
コマンド
}
※ コマンドの後ろには「;」をつけます。
※注意※
「{
」 の後ろと「}
」の前には半角スペースが必要になります。
関数を定義する際は、各コマンドの後に;
あるいは開業が必要です。
※ シェルスクリプトでは「;」は必要ありません。
例えば、テキストファイルのみをリスト表示するlstxt関数は以下のように定義されます。
- コマンドラインの場合
lstxt() { ls -l | grep '.txt$'; }
- シェルスクリプトの場合
#!/bin/bash
lstxt()
{
ls -l | grep '.txt$'
}
関数の実行には、コマンドを実行するのと同じように関数名を入力します。関数が利用できるのは、関数を定義したシェル内のみとなります。bashで変数と関数名の名前が重複すると予期せぬ動作をする可能性があることに注意してください。定義されている関数を表示するには、declare -f
コマンドを使用します。
#!/bin/bash
declare -f lstxt
lstxt ()
{
ls --color=auto -l | grep '.txt$'
}
関数を削除したい場合は、変数を削除するのと同様に、unset
コマンドを使用します。
unset -f lstxt
引数の定義
シェルスクリプトで引数を利用することで、引数に応じて処理を変えることができます。シェルスクリプトの実行時に引数を渡すと、その処理が参照されます。引数を参照させるには以下に示す特殊な変数を用います。
変数名 | 説明 |
---|---|
$0 | シェルスクリプトのファイル名 |
$n | nに引数を指定できる。10以上の値の場合は{}で囲う |
$# | 引数の数 |
$@ | 全ての引数(スペース区切り) |
$* | 全ての引数(区切りは環境変数IFSで指定されたもの) |
他にも引数を操作するshift
コマンドがあります。このコマンドは引数の位置パラメーターを任意の数左にシフトするコマンドです。例えば引数に$1、$2、$3があった場合、$1に$2の内容が送られ、$2に$3の内容が送られる、といったようにシフトします。ただし、シフトした時に元々の引数の内容は失われますので、元の内容が必要な場合は別途退避させておく必要があります。
例)argstest
シェルスクリプト
#!/bin/bash
# それぞれに変数を指定
echo "script=" $0
echo "No.1=" $1
echo "No.2=" $2
echo "count=" $#
echo "argsall=" $@
# argstestの実行時に引数を渡す
bash argstest aaa bbb ccc
script= argstest # 変数$0の内容
No.1= aaa # 変数$1の内容
No.2= bbb # 変数$2の内容
count= 3 # 変数$#の内容
argsall= aaa bbb ccc # 変数$@の内容
戻り値
戻り値は、コマンド終了後に、そのコマンドが成功したか失敗したかを表す数値です。特殊変数「$?」変数に自動的に格納されます。一般的には成功時には「0」、失敗時には「0」以外の数値となります。以下の例では、コマンドがエラーとなったため、戻り値が2となっています。
ls -l file1
ls: cannot access 'file1': No such file or directory
echo $?
2
exit
コマンドを使用し、戻り値をシェルスクリプト内で定義することもできます。後述する条件分岐など、処理結果によって任意の終了ステータスを設定し、シェルスクリプトや関数を終了させたい場合に利用します。終了ステータスに指定できる数値は0〜255までの整数値です。コマンドの成功時には「0」、失敗時には「1」を設定するのが慣例となっています。
例)カレントディレクトリにhoge.shが存在するかどうかをチェックするシェルスクリプト
#!/bin/bash
if [ -e ./hoge.sh ] then
echo "ディレクトリに存在します。"
exit 0
else
echo "ディレクトリに存在しません。"
echo 1
fi
条件分岐
シェルスクリプトでは、条件によって処理を分岐させることができます。一般的なプログラミング言語と同様にif
文やcase
文を使って記述します。
if
文を使った書式
if コマンド
then
実行文1
else
実行文2
fi
コマンドの終了ステータスが0の場合、then
の実行文1が実行されます。それ以外の場合はelse
の実行文2が実行されます。
また、「;
」を使うことにより、1行で複数のコマンドを記述できます。
then
はif
コマンドと異なるコマンドのため、本来は分けて記述する必要がありますが、「;
」を使用することにより繋げることができます。
この書式の場合、条件式の箇所には[]
をつけ、条件式の左右には半角スペースを入れます。また、if
と[]
の間にも半角スペースが必要です。if[]
や[条件式]
のように詰めて記述してしまうとエラーになりますので注意してください。
if [ 条件式 ] ; then
実行文1
else
実行文2
fi
case
文を使った書式
式の値に応じて複数に分岐する場合は、if
文よりもcase
文を使うと便利になります。
case 式 in
値1)
実行文1 ;;
値2)
実行文2 ;;
・
・
・
esac
case文は実行文の末尾に「;;
」を、最後に「esac
」をつけます。
繰り返し処理
一定回数の処理を繰り返し実行する場合や、条件が満たされている間処理を続ける場合、繰り返し処理を行うことができます。一般的なプログラミング言語同様に、for
文やwhile
文を使用します。
for
文を使った書式
for
文は処理回数や処理を実行したい対象が明確になっている場合に使用します。対象の値をリスト形式で羅列し、変数に値を代入して処理というのを、値の個数分だけ繰り返して処理を実行します。全ての値に対して処理が完了するとループは終了します。
for 変数名 in 変数に代入する値のリスト
do
実行文
done
seq
コマンドを使うと連続した数値を自動生成できます。繰り返し実行したい回数が多い場合、seq
コマンドでコンパクトに記述することができます。
for i in 'seq 10 15' # 10~15の値を自動生成
do
echo $i
done
while
文を使った書式
while文はある条件が成り立っている間のみ処理を実行するといったように、不定回数の繰り返し処理を実行する場合に使用します。指定された条件文の終了ステータスを判定して、結果が真の場合処理を実行します。真の結果が続く限り処理が継続して行われ、結果が偽になった時に処理を終了します。
while 条件文
do
実行文
done
Bashスクリプトの実行とデバッグ
Bashスクリプトの実行
bashスクリプトの実行方法は大きく分けて二つあります。
- bashコマンドにスクリプトを指定する
- ファイルを直接実行する
1. bashコマンドにスクリプトを指定する
bash
コマンドにシェルスクリプトのファイル名を指定して実行します。
bash hoge.sh
2. ファイルを直接実行する
シェルスクリプトを直接実行することができます。実行するためには以下の二つの条件が必要となります。
-
ファイルのパーミッションに実行権限がある
パーミッションとはファイルの権限を管理するためのものです。ファイルの所有者や所有者のグループなどに対してファイルの権限を付与します。実行する権限が付与されていないファイルは実行することができません。権限がない場合は、
chmod
コマンドを使い、実行権限を付与する必要があります。
※権限に関してはこちらの記事で詳しく解説しています。
ls -l
# 実行権限を表す「x」がない
-rw-r--r-- 1 envader envader 0 6月 20 04:17 hoge.sh
chmod u+x hoge.sh # 所有者の属性に実行権限を付与
ls -l
# 所有者に実行権限が付与されたので、このファイルはコマンドとして実行できる
-rwxr--r-- 1 envader envader 0 6月 20 04:17 hoge.sh
シェルがファイルの場所を特定して実行するには、以下のどちらかを満たしている必要があります。
- フルパスもしくは相対パスを使って明示的に場所を指定する
- 環境変数$PATHに設定されているディレクトリ内にファイルを置く
このどちらかの条件が満たされていなければ、カレントディレクトリにファイルがあっても、コマンドとして実行することはできません。
bashスクリプトのデバッグ
bashコマンドの-x
オプションと-v
オプションを使うと、デバッグをすることができます。
-x
オプション
シェルスクリプト内で実際に実行されたコマンドを表示します。変数が使用されている場合は、その変数の値が展開されて表示されます。先頭の「+
」はシェルスクリプトで実行されたコマンド、「++
」は 「``」 (バッククォート)内で実行されたコマンドとなっています。
例)数値のみを変数に書くシェルスクリプトをデバッグする
cat ./debug.sh
bash -x ./debug.sh
++ date +%S
+ var1=40
++ wc -l
++ ls -l
+ var2=8
+ '[' 40 -ge 30 ']'
+ var3=BIG
+ exit 0
-v
オプション
シェルスクリプト内でこれから実行されるコマンドを表示します。変数が使用されている場合は-x
オプションと異なり、変数名が表示されます。-v
オプションは、-x
オプションと併用して使用されることが多いです。
bash -vx ./debug.sh
#!/bin/bash
var1=`date +%S`
++ date +%S
+ var1=33
var2=`ls -l | wc -l`
++ wc -l
++ ls -l
+ var2=2
if [ $var1 -ge 30 ]; then
var3="BIG"
else
var3="SMALL"
fi
+ '[' 33 -ge 30 ']'
+ var3=BIG
exit 0
+ exit 0
まとめ
シェルスクリプトについて解説しました。シェルスクリプトは頻繁に使うコマンドや一連のコマンドをまとめたプログラムです。シェルスクリプトでは以下の機能が使えます。
- 関数
- 引数
- 戻り値
- 条件分岐(
if
/case
) - 繰り返し(
for
/while
)
シェルスクリプトの実行にはbash
コマンドを使用して実行する方法と、コマンドとして実行する方法があります。コマンドとして実行する場合は、パーミッションに実行権限があることと、フルパスもしくは相対パスを使うか、環境変数PATH
にファイルの置き場所を指定して、ファイルの場所を明確にする必要があります。
bash
コマンドに-x
オプションあるいは-v
オプションをつけることでデバッグを実行できます。-x
オプションと-v
オプションは併用されることが多いです。
記事の内容は理解できましたか?