はじめに
- Bash
- Zsh
- Python
- JavaScript
- PHP
- Perl
- Ruby
などの他のソフトウェアの動作を制御するために使用されるプログラミング言語を スクリプト言語 と言う。
スクリプト言語で記述されたプログラムは スクリプト と呼ばれ、以下の拡張子が使用される。
-
.sh
: Bash, Zsh など -
.py
: Python -
.pl
: Perl -
.rb
: Ruby -
.js
: JavaScript
Bash、Zsh、sh で記述されたスクリプトファイルの拡張子には、慣習的に .sh
が使用される。
また、OSの動作を制御するための Bash、 Zsh、 sh で記述されたスクリプトを特に シェルスクリプト と言う。Windows では、シェルスクリプトは バッチファイル と呼ばれる。
スクリプトはインタプリタによって逐次解釈・実行されるため、実行前にコンパイルを行う必要がない。
実行環境には、それぞれの言語に対応するインタプリタが必要だが、Bash(言語)のようなシェルスクリプトはシェル(Bash)自身が解釈・実行する。
シバン(shebang)/ #!
スクリプトファイルの先頭に記述する記号を shebang(シバン)と言う。
shebang によって、どのインタプリタを使用して実行するかを指定することができる。
#!/bin/bash
...ここにスクリプトを記述する...
shebang に記述する言語はシェルスクリプトに限定されない。
#!/usr/bin/env python3
...ここにPythonでスクリプトを記述...
以下の場合には shebang は無視される。
$ bash myscript.sh
$ source myscript.sh
$ . myscript.sh
スクリプトファイルの実行方法
スクリプトファイルを実行する方法にはいくつかある。
これらの方法は バイナリファイル には適用できない。
実行権限を付与する
スクリプトファイルは $ chmod
コマンドを使用して読み取り権限(r
)、実行権限(x
)を付与することによって、実行可能ファイル になる(バイナリファイルの実行は 実行権限 のみで良い)。
$ chmod +rx myscript.sh
$ bash
や $ source
の引数に渡して実行する場合には、読み取り権限(r
)だけで実行できる。
実行する
実行権限を付与したファイルは、起動しているシェル上で実行することができる。
$ ./myscript.sh # myscript.sh がカレントディレクトリにある場合
スクリプトファイルが Bash によって記述されている場合、$ bash
コマンドを使用して実行することもできる。この場合、ファイルに実行権限を付与する必要はなく 読み取り権限のみで良い。
$ bash myscript.sh
$ bash
コマンドと同様に $ source
コマンドを利用する場合も、ファイルに実行権限を付与する必要はなく読み取り権限のみで良い。
$ source myscript.sh
また .
コマンドは $ source
コマンドと同じ機能を持つため、$ .
を利用しても良い。
$ . myscript.sh
テキスト形式のスクリプトは、読み取り 権限があれば良い。
バイナリ形式のスクリプトは、実行 権限が必要。
デバッグモード
シェルスクリプトには デバッグモード と呼ばれる実行モードがあり、デバッグモードで実行すると、スクリプト内で実行される各コマンドが実行前に表示される。
$ bash -x スクリプト
スクリプトファイルの shebang に -x
を記述する方法でもデバッグモードで実行することができる。
#!/bin/bash -x
スクリプトの途中でデバッグモードへと切り替えたい場合、$ set -x
を実行する。
set -x # この行以降がデバッグモードで実行される
また同様に、スクリプトファイル中で元に戻すこともできる。
set +x # この行以降、デバッグモードが解除される
構文チェック
$ set
コマンドの -n
オプションを使用すると、スクリプトを実行せずに構文エラーがないかをチェックすることができる。
$ set -n スクリプトファイル
配列
配列名[インデックス]
の形で配列を扱うことができる。インデックスは 0
が最小値。
$ 配列変数名[インデックス]=要素
$ array[0]="apple"
$ array[1]="banana"
$ array[2]="orange"
$ 配列変数名=(要素1 要素2 要素3)
$ array=(apple banana orange)
要素を取り出す際は 変数の展開 を利用する。
$ array=(apple banana orange)
$ echo ${array[0]}
apple
@
/ *
インデックスに @
もしくは *
を使用すると、配列内のすべての要素を展開できる。
$ array=(apple banana orange)
$ echo array[@]
apple banana orange
スライス
$ array=(apple banana orange grape strawberry)
$ echo ${array[@]:0:3}
apple banana orange
配列の長さ
#配列変数名
とすると、配列の長さ(要素数)を取得できる。
$ echo ${#array}
要素の追加
+=
演算子を使うことで配列に要素を追加できる。
$ array=(apple banana orange)
$ array+=(grape mango)
$ echo array[@]
apple banana orange grape mango
要素の削除
特定の要素を削除するには $ unset
を使う。
$ unset 配列変数名[インデックス]
配列の削除
$ unset 配列変数名
条件分岐
if [ 条件式 ]; then
コマンド
elif [ 条件式 ]; then
コマンド
else
コマンド
fi
;
は改行によって省略することもできる。
if [ 条件式 ]
then
処理
elif [ 条件式 ]
then
処理
else
処理
fi
$ test
条件式を評価して真(0
)または偽(1
)を返すシェル組み込みコマンド。
多くのプログラミング言語では true
を 1
で表現するが、シェルスクリプトでは 終了ステータス に由来して、成功(真)が 0
となっている。
$ test 条件式
$ test
には エイリアス [
が存在するため、以下のようにすることもできる。
$ [ 条件式 ]
閉める ]
は引数として扱われ、条件式を終了させる役割を持つ。[
はコマンドとして機能しているため、[
の後ろにスペースを入れなければならない。
また [[ 条件式 ]]
では &&
や ||
など機能が豊富なため、[ 条件式 ]
よりも [[ 条件式 ]]
の利用が推奨されている。
$ [[ 条件式 ]]
[ 条件式 ]
よりも [[ 条件式 ]]
の利用が推奨される。
文字列の比較
$ test -z 文字列
$ test -n 文字列
$ test 文字列1 = 文字列2
$ test 文字列1 != 文字列2
以下は [[ 条件式 ]]
でのみ使用できる。
$ [[ 文字列1 == 文字列2 ]]
$ [[ 文字列1 != 文字列2 ]]
$ [[ 文字列 == a*ple ]]
$ [[ 文字列 =~ 正規表現 ]]
数値の比較
$ test 数値1 -eq 数値2
$ test 数値1 -ne 数値2
$ test 数値1 -gt 数値2
$ test 数値1 -ge 数値2
$ test 数値1 -lt 数値2
$ test 数値1 -le 数値2
ファイルの比較、存在チェック
$ test -e ファイル
$ test -f ファイル # デバイスファイルは偽
$ test -d ディレクトリ
$ test -s ファイル
$ test -r ファイル
$ test -w ファイル
$ test -x ファイル
$ test -L ファイル
$ test ファイル1 -nt ファイル2
$ test ファイル1 -ot ファイル2
条件の組み合わせ
$ test !条件式
$ test 条件式1 -a 条件式2
$ test 条件式1 -o 条件式2
$ [ 条件式1 ] && [ 条件式2 ] # 条件式1 が真の場合のみ 条件式2 が評価される
$ [ 条件式1 ] || [ 条件式2 ] # 条件式1 が偽の場合のみ 条件式2 が評価される
以下は [[ 条件式 ]]
でのみ使用できる。
$ [[ 条件式1 && 条件式2 ]]
$ [[ 条件式1 || 条件式2 ]]
case
文
case 式 in
値1)
処理 ;;
値2)
処理 ;;
*) # default のとき
処理 ;;
esac
パターンにはワイルドカード(*
)を使用することができる。
esac
は case
のスペルを反転させたもの。
評価された「式」と、「値」との比較で条件を分岐させる。
for
文
for 変数 in 要素1 要素2 要素3; do
処理
done
;
は改行によって省略することができる。
for 変数 in 要素1 要素2 要素3
do
処理
done
要素1 要素2 要素3
の部分には 配列 を使用することができる(要素を 展開 させる必要がある)。
for 変数 in ${配列変数[@]}
do
処理
done
Bash
ではC言語のような構文がサポートされているため、以下のように書くこともできる。
for ((i = 1; i <= 5; i++))
do
処理
done
$ seq
コマンドを利用することで範囲を指定した for
文を実現できる。
for i in $(seq 1 5)
do
処理
done
ブレース展開 を利用することもできる。
for i in {1..5}
do
処理
done
break
/ continue
繰り返し処理を break;
によって抜けたり、continue;
によって以降の処理を実行せず次の繰り返し処理へ進むこともできる。
;
は改行によって省略することができる。
ブレース展開
Brace Expansion
文字列のリストを展開するための機能。
$ echo {A, B, C}
A, B, C
$ echo file_{A, B, C}.txt
file_A.txt file_B.txt file_C.txt
$ echo {A..E}
A B C D E
$ echo {1..5}
1 2 3 4 5
$ echo file{1..3}.txt
file1.txt file2.txt file3.txt
$ echo {1..10..2}
1 3 5 7 9
$ seq
$ seq 最後の値
$ seq 最初の値 最後の値
$ seq 最初の値 増分 最後の値
while
文
while [ 条件式 ]; do
処理
done
;
は改行によって省略することができる。
while [ 条件式 ]
do
処理
done
break;
でループを抜ける無限ループを利用することもできる。
while true
do
if [ 条件式 ]
then
break;
fi
done
関数
関数名() {
処理
}
$ function
を使った定義。
function 関数名() {
処理1
処理2
処理3;
}
※ function
で定義する場合、処理の末尾にはセミコロン ;
を記載する
return
return
を使用した場合、関数の処理を途中で終了させることができる。
関数名() {
if [ 条件式 ]; then
return;
fi
}
またスクリプトファイルで関数を実行した場合、関数内で最後に使用したコマンドの 終了ステータス が関数の終了ステータスになるが、これを return
で明示的に指定することができる。
関数名() {
return 終了ステータス;
}
「終了ステータス」と「戻り値」は別のものである点に注意。
戻り値
シェルスクリプトの関数では $ echo
を使って何らかの値を戻すことが一般的。
関数名() {
echo 値
}
$ echo
に渡された値は 標準出力 に吐き出されるため、=
を使って変数に代入することができる。
変数=関数 # 関数内で $ echo によって返した値が変数に代入される
また return
で返せる値は 終了ステータス 0
~ 255
だけである点に注意。終了ステータスは ビルトインシェル変数 の $?
で参照する。
return
で返せるのは 終了ステータス。
関数を呼び出す
関数名
関数名 引数1 引数2 引数3
関数の実行時に渡した引数は、関数内で ビルトインシェル変数 の $1
、$2
などで参照することができる。
関数名() {
echo $1 # 1つ目に渡された引数
echo $2 # 2つ目に渡された引数
}
関数の外側のスコープでは $1
、$2
には コマンドライン引数 が格納されている。そのため、コマンドライン引数として渡した値は、関数の外からしか参照できないという点。
もしコマンドライン引数を関数内で使用したい場合、以下のように、一度関数の外で変数に移し替える必要がある。
$ bash スクリプトファイル 引数1 引数2
var=$1 # 一度変数に移し替える
関数() {
var が使える
}
コマンドライン引数で渡した引数は、関数の外でしか参照できない
$ exit
スクリプトの実行を即座に終了する。
$ exit
引数に 終了ステータス を指定することで、呼び出し元に終了ステータスを返却することができる。
$ exit 終了ステータス
$ exit
コマンドの終了ステータスには、直前のコマンドの $? をそのまま引数として渡すこともできる。
$ exit $?
コマンドライン引数
コマンド、もしくは スクリプトの実行時に指定することができる引数。
オプションもコマンドライン引数の一つ。
$ コマンド 引数1 引数2
$ スクリプトファイル 引数1 引数2
指定した引数は、スクリプトファイル中で $1
、$2
、$3
のように参照できる(ビルトインシェル変数)。
$ getopts
コマンドラインオプションを解析できる組み込みコマンド($ getopt
は 外部コマンド)。
シェルスクリプト内で オプション引数 を実現するために利用される。
オプション引数とは以下の部分のように、オプションが受け取る引数 のことを指す。
$ コマンド -オプション オプション引数
$ getopts オプションの仕様 変数名
オプションの仕様
各オプションを 1 文字で指定する。指定した文字の後ろにコロン :
の有無が、そのオプションが引数を取るかどうかを表す。
具体的には、引数が必要なオプションについてはコロン :
を付ける。:
が指定されていた場合、オプション引数は $OPTARG
で取得することができる。
反対に、引数が必要ないオプションはコロン :
をつけない。
変数名
解析したオプションの名前を格納する変数。
while getopts "a" opt
do
case $opt in
a)
処理 ;; # -a が指定された時の処理
\?)
処理 ;; # 無効なオプションが指定された時のエラー処理
esac
done
※ 無効なオプション /?
?
はワイルドカードでも使用されるため、\
でエスケープしている。?
は特殊文字などではなく単なる文字列で、慣習的に \?
で「不明な引数」を表現している。
while getopts "a:" opt; do
case $opt in
a)
処理 ;; # -a のオプション引数を $OPTARG で参照できる
\?)
処理 ;; # 無効なオプションが指定された場合のエラー処理
esac
done
Tips
関数を複数定義するような場合、主となる処理を main()
関数でまとめる方法がよく使用される。
main() {
関数1
関数2
}
関数1() {
処理
}
関数2() {
処理
}
main # 関数の実行