シェルスクリプトを使ってみたいんだ!
でも使うのは初めてなんだよね・・・
初心者でも分かりやすいように、
シェルスクリプトの基本から使い方まで丁寧に解説するね!
シェルの基本
シェルとは?
シェルとはOSと対話するためのインターフェース(窓口)です。
シェルはクライアントから入力されたコマンドの内容をカーネルが分かるように解釈し、それをカーネルに伝えます。
シェルはOSの核であるカーネルとやり取りをし、コマンドなどを制御するものです。
一言で表現すると「クライントからの入力とパソコンからの出力を伝達する」のがシェルです。
カーネルとは?
カーネルとはOSの核となるもので、メモリ管理やプロセス管理などOSの中心的な機能を担っています。
カーネルはシェルから受け取った内容を処理し、その結果をシェルに返します。
シェルは返ってきた内容が分かるように翻訳し、それをクライアントに返します。
カーネルを覆っている殻がシェルだよ!
- シェルがあることでコマンドを受け付けることができOSとの対話ができる
- CUI環境においてシェルは最も身近なインターフェースである
なぜカーネルはシェルに覆われているの?
わざわざシェルで覆う必要ってあるの?
カーネルをシェルで覆っているのは利便性と安全性を高めるためだよ!
- 使う人によってシェルをカスタマイズできるため、使い勝手が良くなる
- シェルに問題があったとき、カーネルへの影響を少なくできる
シェルの種類
シェルには複数の種類があります。
どのシェルもクライアントとカーネルのやり取りをする役割としては同じですが、それぞれのシェルには特徴があります。
シェル | 説明 |
---|---|
sh (Bourne Shell) | もっとも古くからあるシェルで、標準的なシェルです。 シンプルに使うことができますが、少し機能が足りないことも多く、 対話的に使うときには向いていません。 このシェルは「Bシェル(Bsh)」と呼ばれ、様々な派生のシェルが作られています。 |
bash (Born again shell) | Bshを元にして機能を拡張したシェルです。 ユーザーインターフェースとしての機能が強化されています。 Bシェルと互換性があるため、Bシェルを置き換えることができます。 |
zsh (Z shell) | bashなど他のシェルの機能を更に便利に使えるように拡張したZシェルです。 独自の拡張機能も備えています。 多機能なため使い方が他のシェルと比べて難しいことがありますが、 その分いろんな機能を使えることができます。 |
fish (Friendly Interactive Shell) | 対話的な操作ができ、分かりやすさに重視しているシェルです。 補完機能に強みがあります。 |
ターミナルとは?
ターミナルとは、クライアントからパソコンへ命令を送るためのツールです。
コマンドを入力してパソコンに指示を与えます。
ターミナル上では、マウスやトラックパッドを使わずに、キーボードで直接コマンドを入力して操作します。
シェルスクリプトとは?
本題のシェルスクリプトについて解説していくね!
シェルスクリプトとは、シェルの操作がまとめられたプログラムです。
LinuxやUnixでは、キーボードを使った文字入力によってOSを操作します。
これはCUI(Character User Interface)と呼ばれる文字ベースのインタフェースが標準なためです。
MacやWindowsのような画面クリック操作ができるGUI(Graphical User Interface)ではありません。
通常はクライアントがコマンドを入力してOSを操作し、OSへの要求と結果を対話的に行います。
シェルスクリプトなしでも、1つのコマンドを入力することでOSを操作することができます。
しかし、長いコマンドや同じコマンドを毎回入力するのは手間で煩雑です。
複数のコマンドを実行したいときも前のコマンドの処理が終了してからでないと次のコマンドを入力できません。
シェルスクリプトを使うことで、そういった一連のコマンドをまとめて記述することができ、効率的にOSを操作することが可能となります。
シェルスクリプトでできること
cronを使った定期的な処理
cronはUNIX系のOSに標準的に搭載されている機能で、設定したスケジュールに従って指定したプログラムを定期的に実行してくれるものです。
cronでは、分・時間・日・月・曜日単位でスケジュールを設定できるため、決まった日時にプログラムを自動的に実行できます。
シェルスクリプトでcronのプログラムを記述することで自由に定期処理を設定することができます。
ログファイルなどの内容を抽出
ログファイルなどのファイルの内容を抽出するときはgrepコマンドなどを使いますが、複雑な処理をしようとすると、コマンドを何度も入力しなければいけません。
内容を抽出するコマンドをシェルスクリプトでまとめて記述しておけば、簡単に内容を抽出することができます。
アプリケーションと連携
シェルスクリプトはアプリケーションの動作を操作することができます。
起動・停止・再起動などシェルスクリプトで制御することが可能です。
またRubyやPHPなどのプログラミング言語とも連携ができ、アプリケーションをより高機能にしたり使いやすくしたりすることが可能です。
アプリケーションのデプロイ処理に利用されることもあります。
シェルスクリプトの使い方
ファイルの作成
最初の一行目に#!/bin/sh
を記述しシェルスクリプトを記述することを宣言します。
これは「シバン」と呼ばれる文字列で、シェルスクリプトであることを宣言するためのものです。
(「bash」の独自機能を使う場合は#!/bin/bash
と記述します)
ファイルの拡張子は.sh
にします。
#!/bin/sh
echo "Hello, World!"
ファイルの実行
まずはchmodコマンドを使ってシェルファイルに実行権限を与えます。
chmod 755 sample.sh
実行権限を与えると「./
+シェルファイル名」でファイルを実行できるようになります。
./sample.sh
実行権限を与えなくても以下のように実行可能ですが、実行権限を与えるのが一般的です。
sh sample.sh
bash sample.sh
コメントアウト
#
を付けることでコメントを書くことができます。
#!/bin/sh
# これはコメントです。
# echo "コメントは実行されません。"
echo "Hello, World!"
入出力
read 変数名
read
で入力値を受け取り、echo
で出力をすることができます。
#!/bin/sh
echo -n "Enter your name: "
read NAME
echo "Entered name: $NAME"
$ sh ./enter_name.sh
Enter your name: Taro
Entered name: Taro
変数
変数=値
変数は値を入れておく箱です。変数を使うときにはルールがあります。
- 半角英数字とアンダースコアのみ使える(
a~z
、A~Z
、0~9
、_
) - 値を与えるときは
=
の前後は空白なしで記述する - 文字列は
""
で囲む - 変数にアクセスするときは変数名の前に
$
を入れるか$
入れて変数を{}
で囲む - 1つの変数に1つの値しか保存できない
- 変数の値を上書きされなたくないときは
readonly
を使う - 変数を
unset
で削除することができる(readonly
変数を削除することはできない)
#!/bin/sh
var="これは変数です。"
var2="これは2つ目の変数です。"
echo "var=$var"
echo "var2=$var2"
var2="var2が変更されました。"
echo ${var2}
readonly var
var="readonly varを変更する"
$ ./variable.sh
var=こは変数です。
var2=これは2つ目の変数です。
var2が変更されました。
variable.sh: line 12: var: readonly variable
特別な変数
変数には状態を保持している特別な変数があるよ!
変数 | 説明 |
---|---|
$0 | スクリプト名 |
$1 ~$9 | 引数を参照、1番目の引数を「$1」、2番目の引数を「$2」で参照できる |
$# | スクリプトに与えた引数の数 |
$* | 全ての引数 |
$@ | 基本的に「$*」と同じで「””」で囲んだときの展開動作が異なる |
$? | 直前実行したコマンドの終了値(0: 成功、1: 失敗) |
$$ | スクリプトのプロセスID |
$! | 最後に実行したバックグラウンドプロセスID |
#!/bin/sh
echo "\$0(スクリプト名): $0"
echo "\$1(1番目の引数): $1"
echo "\$2(2番目の引数): $2"
echo "\$#(引数の数): $#"
echo "\"\$*\": \"$*\""
echo "\"\$@\": \"$@\""
echo $?
$ ./special_variable.sh first second third
$0(スクリプト名): special_variable.sh
$1(1番目の引数): first
$2(2番目の引数): second
$#(引数の数): 3
"$*": "first second third"
"$@": "first second third"
0
変数の展開・置換
変数 | 説明 |
---|---|
${var} | var変数へアクセス |
${var:-dummy} | var変数がブランクまたは空文字列のとき「dummy」を返す(varに保存しない) |
${var:=dummy} | var変数がブランクまたは空文字列のとき「dummy」を返す(varに保存する) |
${var:+dummy} | var変数がセットされているとき「dummy」を返す(varに保存しない) |
${var:n} | var変数のn文字目(0始まり)以降の文字列 |
${var:n:m} | var変数のn文字目(0始まり)からm文字分の文字列 |
${var^} | 最初の1文字を大文字にする |
${var^^} | 全ての文字を大文字にする |
${var,} | 最初の1文字を小文字にする |
${var,,} | 全ての文字を小文字にする |
${var~} | 最初の1文字を大文字・小文字に反転する |
${var~~} | 全ての文字を大文字・小文字に反転する |
#!/bin/sh
var="text"
echo "1: ${var}"
var=""
echo "2-1: ${var:-dummy}"
echo "2-2: var = ${var}"
echo "3-1: ${var:=dummy}"
echo "3-2: var = ${var}"
var="text"
echo "4: ${var:+dummy}"
var="text"
echo "5: ${var:2}"
echo "6: ${var:0:2}"
var="text"
echo "7: ${var^}"
echo "8: ${var^^}"
var="TEXT"
echo "9: ${var,}"
echo "10: ${var,,}"
var="TeXt"
echo "11: ${var~}"
echo "12: ${var~~}"
$ ./expand_replace_variable.sh
1: text
2-1: dummy
2-2: var =
3-1: dummy
3-2: var = dummy
4: dummy
5: xt
6: te
7: Text
8: TEXT
9: tEXT
10: text
11: teXt
12: tExT
四則演算
シェルでは算術演算子をexpr 数字演算子 数字
で計算できます。
演算子 | 例 |
---|---|
+ | echo `expr 10 + 20` → 30 |
- | echo `expr 20 - 10` → 10 |
\* | echo `expr 2 \* 3` → 6 |
/ | echo `expr 10 / 2` → 5 |
% | echo `expr 10 % 4` → 2 |
if文
if 条件; then 処理 fi
if文は与えられた条件が真のときに処理を行い、偽のときは別の処理(elif
やelse
)またはスキップを行う条件分岐をするための制御文です。
if文の条件式では、test
コマンドを使うのが一般的です。
また;
は1行で複数のコマンドを記述するための記号です。
thenはifとは異なるコマンドであるため、;
を使って繋げて記述しています。
繋げなくても記述できますが、繋げて記述するのが一般的です。
testコマンド
testコマンドは条件式の結果を評価するコマンドで、評価した結果を0(真)か1(偽)で返します。
test 1 -eq 1
echo $?
-eqは等しいか評価する条件式で、$?は直前のコマンドの実行結果を返します。
上記の例は1と1は等しいので0(真)となります。
testコマンドの略式として[]
が使えます。
[
と]
の間にはスペースを入れます。スペースがないとエラーになるので注意しましょう。
#!/bin/sh
if [ 条件式1 ]; then
echo "条件式1が真になったのときの処理"
elif [ 条件式2 ]; then
echo "条件式2が真になったのときの処理"
else
echo "条件式1と条件式2が偽になったときの処理"
fi
数値比較演算子
数値を比較するときは専用の記号を使います。
演算子 | 例 | 説明 |
---|---|---|
-eq | [ 数値1 -eq 数値2 ] | 数値1と数値2が等しいとき真を返す |
-ne | [ 数値1 -ne 数値2 ] | 数値1と数値2が異なるとき真を返す |
-gt | [ 数値1 -gt 数値2 ] | 数値1が数値2より大きいとき真を返す |
-lt | [ 数値1 -lt 数値2 ] | 数値1が数値2より小さいとき真を返す |
-ge | [ 数値1 -ge 数値2 ] | 数値1が数値2より大きいか等しいとき真を返す |
-le | [ 数値1 -le 数値2 ] | 数値1が数値2より小さいか等しいとき真を返す |
#!/bin/sh
[ 1 -eq 1 ]; echo "-eq: $?"
[ 1 -ne 1 ]; echo "-ne: $?"
[ 2 -gt 1 ]; echo "-gt: $?"
[ 1 -lt 2 ]; echo "-lt: $?"
[ 1 -ge 1 ]; echo "-ge: $?"
[ 1 -le 2 ]; echo "-le: $?"
$ ./number_operator.sh
-eq: 0
-ne: 1
-gt: 0
-lt: 0
-ge: 0
-le: 0
文字列比較演算子
文字列を比較するときの演算子です。-n
や-z
を使わなくても同じ結果になる記述もあります。
演算子 | 例 | 説明 |
---|---|---|
文字列 | [ 文字列 ] | 文字列の長さが0より大きいとき真を返す |
-n | [ -n 文字列 ] | 文字列の長さが0より大きいとき真を返す |
!文字列 | [ !文字列 ] | 文字列の長さが0のとき真を返す |
-z | [ -z 文字列 ] | 文字列の長さが0のとき真を返す |
= | [ 文字列1 = 文字列2 ] | 2つの文字列が等しいとき真を返す |
!= | [ 文字列1 != 文字列2 ] | 2つの文字列が異なるとき真を返す |
#!/bin/sh
[ "text" ]; echo "文字列: $?"
[ -n "" ]; echo "-n: $?"
[ !"text" ]; echo "!文字列: $?"
[ -z "text" ]; echo "-z: $?"
[ "text" = "text" ]; echo "=: $?"
[ "text" != "text" ]; echo "!=: $?"
$ ./string_operator.sh
文字列: 0
-n: 1
!文字列: 0
-z: 1
=: 0
!=: 1
条件演算子
演算子 | 例 | 説明 |
---|---|---|
! | [ ! 条件 ] | 条件式が偽のとき真を返す |
-a | [ 条件1 -a 条件2 ] | 両方の条件式が真のとき真を返す(and) |
&& | 両方の条件式が真のとき真を返す(and) | |
-o | [ 条件1 -o 条件2 ] | いずれかの条件式が真のとき真を返す(or) |
|| | いずれかの条件式が真のとき真を返す(or) |
#!/bin/sh
! [ 1 -eq 1 ]; echo "!: $?"
[ 1 -eq 1 -a 2 -eq 2 ]; echo "-a: $?"
[ 1 -eq 1 ] && [ 2 -eq 2 ]; echo "&&: $?"
[ 1 -eq 1 -o 5 -eq 10 ]; echo "-o: $?"
[ 1 -eq 1 ] || [ 5 -eq 10 ]; echo "||: $?"
$ ./condition_operator.sh
!: 1
-a: 0
&&: 0
-o: 0
||: 0
ファイル演算子
ファイルの状態を判定することができます。
演算子 | 例 | 説明 |
---|---|---|
-d | [ -d ファイル名 ] | ディレクトリのとき真を返す |
-f | [ -f ファイル名 ] | 通常ファイルのとき真を返す |
-L | [ -L ファイル名 ] | シンボリックリンクのとき真を返す |
-r | [ -r ファイル名 ] | 読み取り可能ファイルのとき真を返す |
-w | [ -w ファイル名 ] | 書き込み可能ファイルのとき真を返す |
-x | [ -x ファイル名 ] | 実行可能ファイルのとき真を返す |
-s | [ -s ファイル名 ] | サイズが0より大きいとき真を返す |
-nt | [ ファイル1 -nt ファイル2 ] | ファイル1がファイル2より新しいとき真を返す |
-ot | [ ファイル1 -ot ファイル2 ] | ファイル1がファイル2より古いとき真を返す |
switch文
case 変数 in 条件) 処理 ;; esac
switch文は条件に合っているか上から順番に判定します。
条件に一致した時点で処理が終了します。
最後に*
というワイルドカードの記号を指定することで、全ての条件に該当しないときの処理を実行することができます。
;;
は、条件から処理までのひとまとまりの区切りを示しています。
in
、)
、;;
の前後は自由に改行ができます。
#!/bin/sh
drink="coffee"
case $drink in
"water")
echo "水"
;;
"tea")
echo "お茶"
;;
"coffee")
echo "コーヒー"
;;
esac
$ ./switch.sh
コーヒー
while文
while 条件
while文は、指定された条件が「真」の間、繰り返し処理を実行するループ制御文です。
#!/bin/sh
count=0
while [ $count -lt 5 ]
do
echo $count
count=`expr $count + 1`
done
$ ./while.sh
0
1
2
3
4
break
で終了continue
でスキップすることができます。
until文
until 条件
until文は、指定された条件が「偽」の間、繰り返し処理を実行するループ制御文です。
while文と条件が反転した処理を行うことができます。
#!/bin/sh
count=0
until [ $count -gt 5 ]
do
echo $count
count=`expr $count + 1`
done
$ ./until.sh
0
1
2
3
4
5
for文
for 変数 in 値リスト do 処理 done
for文は指定された値に対して一定の回数だけ繰り返し処理をするループ制御文です。
処理する回数や、処理対象が明確なときに使用します。
#!/bin/sh
for var in 0 1 2 3 4
do
echo $var
done
$ ./for.sh
0
1
2
3
4
関数
関数名 () { 処理 }
関数とは一連の処理をまとめた機能のことです。
同じ処理が複数あるときは、その処理を関数化してまとめることで汎用的に使うことができます。
#!/bin/sh
echo_function () {
echo "関数のechoです。"
}
param_function () {
echo "引数1: $1"
echo "引数2: $2"
}
echo_function
param_function param1 param2
$ ./function.sh
関数のechoです。
引数1: param1
引数2: param2
配列(bash)
shでは配列を扱うのが難しいよ。
shでは配列を扱うのが難しいので、配列を簡単に扱えるシェルを使います。
ここではbashで配列を扱う方法を解説します。
配列=(値1 値2 値3 ...)
#!/bin/bash
# bash shellで配列の書き方
array=(item1 item2 item3 item4)
ARRAY[0]="ITEM1"
ARRAY[2]="ITEM3"
echo "ARRAY[0]: ${ARRAY[0]}"
echo "ARRAY[1]: ${ARRAY[1]}"
# 全てのアイテムをアクセスする
echo "ARRAY[*]: ${ARRAY[*]}"
echo "ARRAY[@]: ${ARRAY[@]}"
$ ./array.sh
ARRAY[0]: ITEM1
ARRAY[1]: item2
ARRAY[*]: ITEM1 item2 ITEM3 item4
ARRAY[@]: ITEM1 item2 ITEM3 item4
まとめ
シェルスクリプトの使い方について解説したよ!
- シェルはOSと対話するためのインターフェース
- カーネルはOSの核
- 制御分にはif文、switch文、while文、until文、for文などがある
- コマンド処理を関数化することができる
シェルスクリプトの使い方がイメージできた!