シェルスクリプトは主にUnix系OSのシェルに関わる操作を行うためのスクリプト言語で,ファイル操作やプログラム実行のために書かれます.
このページは,シェルスクリプトの文法を中心に整理しています.

目次

  1. スクリプトの実行
    1. shコマンド
    2. sourceコマンド
    3. シェルスクリプトをコマンドにする
  2. 文法
    1. for文
    2. if文
    3. select文
    4. while文
  3. シェル関数
  4. 配列
  5. パラメータ
    1. デフォルト値
    2. 特殊なパラメータ
    3. 一部除去
  6. リダイレクト
    1. 読み書き
    2. 標準エラー出力
    3. 出力の退避
    4. ヒアドキュメント
    5. ヒアストリング
  7. クォートの違い
  8. グループコマンドとサブシェル
  9. その他
  10. コマンドの利用
    1. オプションを付ける
    2. tmpファイルの作成
    3. スペース区切りされる結果の利用
    4. 小数点を含んだ計算
    5. キーボード入力の読み込み
    6. スクリプトのあるディレクトリを取得する
  11. 参考文献

スクリプトの実行

shコマンド

直接shの引数として,シェルスクリプトを実行することができます.

sh スクリプト

シェルとしてbashを利用したいなら,

bash スクリプト

とします.

sourceコマンド

現在のシェルで引き渡したスクリプトを実行する組み込みコマンドの.コマンドを利用するなら,

. スクリプト

とします.
シェルがbashであるなら,sourceコマンドを用いて

source スクリプト

としても同じです.

引数が存在するときは

source スクリプト 引数1 引数2 …

とします.

シェルスクリプトをコマンドにする

スクリプトを作成する際,1行目を

#!/bin/sh

のように,#!に続けて使用するシェルを宣言します.
この1行目をシバンといいます.
もし/usr/local/bin/bashを使用するなら,シバンは#!/usr/local/bin/bashです.

2行目以下にスクリプトを書き,拡張子shなどで保存します.

作成したスクリプトは

chmod +x スクリプト

で実行権限を付与し,echo $PATHで表示されるパスの通ったところにスクリプトを置きます.

以上で,スクリプトがコマンドとして実行できるようになります.

文法

for文

for i in 配列
do
処理
done

for文を抜けるにはbreakを使います.
次のループに移るには,処理中でcontinueを使います.

数値の場合,配列の例は以下の通りです.

  • 0 1 2
  • {0..2}
  • `seq 0 2`

もしくは1行目自体を次のように書くこともできるかもしれません.

  • for ((i=0; i < 3; i++))

その他,

  • カレントディレクトリの*.txtなど
  • `cat ファイル名`によりファイルから読み込ませた配列
  • 引数全部のセット $@

という指定をすることもできます.

if文

if文は次のように記述します.

if 条件式1
then
処理1
elif 条件式2
then
処理2
else
処理3
fi

ここで,条件式の記述にはtestコマンドを使います.

test 値1 比較方法 値2

この条件式は次のようにも書くこともできます.

[値1 比較方法 値2]

testの結果,真であれば0が返ります.
比較方法は以下の通りです.

  • -eq 等しい
  • -ne 等しくない
  • lt より小さい,gt より大きい
  • le 以下,ge 以上

否定文は

test ! 値1 比較方法 値2

のように!を使って書きます.

ファイルの存在を条件にすることもでき,その真偽は

test -f ファイル名

で判定します.ディレクトリであれば,-d ディレクトリ名です.

また,文字列が等しいかどうかを判定する場合は

test 文字列1 = 文字列2

とし,その否定では!=を使います.

その他,ファイルの更新時刻やユーザーのID,権限等もtestコマンドで確かめることができます.

もし条件が複数存在するなら,ANDであれば

test 条件式1 -a 条件式2

ORであれば

test 条件式1 -o 条件式2

とします.

処理に際して「何もしない」という処理(Pythonでのpass)を行いたいなら,:と書きます.

if文をシンプルに書きたい場合は,三項演算子もどきとして左のパイプラインが真/偽のときに右に進むという性質のある&&||を使うこともできます.
常に使えるわけではありませんが,

[ 条件 ] && trueの処理 || falseの処理

という形です.

select文

select var in item1 item2 item3
do
case $var in
パターンごとの処理
esac
done

延々ループするので,何かの処理ではbreakする必要があります.

case文でパターンごとの処理は以下のように書きます.

casein
パターン1 ) 処理1 ;;
パターン2a | パターン2b ) 処理2 ;; # パターン2a or パターン2b
* ) 処理3 ;; # それ以外のケース
esac

リストを継続実行する場合は以下の通りです.

  • カスケードは文末;;に代えて;&
  • 継続検索は文末;;に代えて;;&

while文

while 条件式
do
処理
done

whileuntilに代えると,until文となります.

breakcontinueでループを抜けたり継続することができます.
while trueで始める無限ループと併せても使う方法もあります.

スクリプトが引数をとる場合,引数をシフトさせるにはshiftを使います.

シェル関数

関数名()
{
リスト
}

シェルスクリプトは関数名のみで使用できます.
括弧は不要です.

リストでlocalコマンドにより宣言した変数はローカル変数となります.

関数と同名の組み込みコマンドがある場合,シェル関数が優先されます.
もし組み込みコマンドを優先したい場合は,該当箇所でbuiltinコマンドを宣言して使います.

配列

次は配列の一例です.

array=(a b)

配列の先頭要素や全要素は次のように取得することができます.

echo ${array[0]}  #始めの要素
a
echo ${array[@]} #全要素
a b

配列の追加は

array+=(値)

で行うことができます.
複数追加も可能です.

要素数は

echo ${#array[@]}

として取得できます.

パラメータ

デフォルト値

あるパラメータが設定されていなかった場合にデフォルト値を代入するのであれば,

${パラメータ=値}

とします.

もしパラメータが空文字列であった場合にも,記号(ここでは=)と同じ処理をさせることを:で表現します.
パラメータが空文字列であった場合に,デフォルト値を代入したいなら,

${パラメータ:=値}

とします(:付きで以下同).

あるパラメータにワンショットである値をはめて使いたいなら,${パラメータ-値}とします.
パラメータが設定されているときのみワンショットである値を使うなら,${パラメータ+値}とします.
それぞれ,パラメータが空文字列であるときにも同じ処理をさせるものとして,:-:+があります.

パラメータ未設定時にエラー終了させたいなら,${パラメータ?値}を使います.
このケースでの値はエラーメッセージです.

特殊なパラメータ

スクリプト実行時の第1引数は$1,第2引数は$2のようにして使用します.
また,引数全ては$@,引数の個数を取得するには$#とします.

$!で直近のバックグラウンド起動のプロセスIDを取得できます.

一部除去

パラメータから一部を切り出すことができます.

次は最長左方除去の例です.
左方除去は#,最長片除去は記号重ね打ちで指定するので,/usr/local/binbinにするには,

example="/use/local/bin"
${example##*/}

とします.

対して,右方除去は%で行います.
最短片除去は記号1つのみで指定するので,text.txttestにする最短右方除去の例は

example="test.txt"
${example%.*}

です.

m文字目からn文字目までパラメータを切り出すには,

${パラメータ:m:n}

とします.
mが指定されていなければ,最初からとなります.
nが指定されていなければ,最後までとなります.

リダイレクト

読み書き

上書き保存形式での書き込みは>によってリダイレクトして,

コマンド > ファイル

とします.
if文やfor文も複合コマンドとしてリダイレクトできます.

追記形式での書き込みには>に代えて>>を使います.

コマンド >> ファイル

読み込むときは<とします.

コマンド < ファイル

読み書き両用オープンは<>です.

コマンド <> ファイル

標準エラー出力

標準エラー出力は2>等でリダイレクトできます.
エラーを捨てるには

コマンド 2> dev/null  #「2>」で標準エラー出力(2番)をリダイレクトする

とします.

ログファイルにアペンドするには2>>とします.

コマンド 2>> ログファイル

標準出力とともにログファイルに書き込むには,

コマンド > ログファイル 2>&1

または

コマンド &> ログファイル

とします.

出力の退避

リダイレクトを応用して出力を退避させる例です.
手順は

  1. 1番から3番にコピー
  2. 1番をファイルに出力
  3. 3番から1番にコピーして,3番を閉じる

という流れになります.

exec 3>&1  #「>&」で左から右へ流し込む
exec > ファイル
処理
exec 1>&3- #「3-」で3番を閉じる

ヒアドキュメント

長文を読み込む場合は,ヒアドキュメントが便利です.
ヒアドキュメントでは,予め指定した文字列が出現するまで読み込みを続けます.
次の例は,EOFという文字列が行頭に現れるまでに読み込んだ文字列を標準入力へリダイレクトします.

cat << 'EOF'
文字列
文字列
EOF

ヒアストリング

ヒアドキュメント同様に長文を読み込むのに適したヒアストリングで3行読ませる例です.

cat <<< '1行目
2行目
3行目'

ヒアストリングでシングルクォートを書きたいなら,

シングルを終える'\''シングル再開

ダブルクォートによるクォート展開する必要があるなら,

シングルを終える'"ダブルで囲まれた部分"'シングル再開

という形を用います.

クォートの違い

シングルクォーテーション'では,囲み内は単純に文字列として扱われる.
ただし,囲みに使っているシングルクォーテーションを打ちたいなら,一度シングルクォーテーションの囲みを閉じて\'を打ち,シングルクォーテーションの囲みを再開する.

ダブルクォーテーション"では,その囲み内で変数とバッククォーテーションによる囲みが使える.
すなわち,エスケープに用いる\に加えて変数に用いる$とバッククォート`は解釈が行われ,他を文字列として扱う.

バッククォーテーション`では,コマンドが有効である.
\$\\\`は特殊解釈する.($()はそうしない.)

グループコマンドとサブシェル

グループコマンドは当シェルで実行されるが,サブシェルは別シェルで実行される.

{
グループコマンド
}
(
サブシェル
)

その他

  • 行末に\で改行しなかった扱いとなります.
  • コマンドはフルパスで指定しておく方がエイリアスが存在していたときに安全です.フルパスはwhich コマンド名で調べることができます.
  • ブレース展開できるなら,echo {a,b}{1,2}a1 a2 b1 b2echo {,1}2なら2 12を返します.

コマンドの利用

オプションを付ける

getoptsコマンドを利用して,シェルスクリプトにオプションを設定する例です.

while getopts オプション opt
do
case $opt in
引数なしオプション ) 処理 ;;
引数ありオプション ) $OPTARGを使った処理 ;;
\? ) echo "Usage: $0 うんたらかんたら" 1>2&
exit 1;;
esac
done

オプションで例えばabc:d:と書けば,4つの一文字オプションを作成します.
オプションのうち,コロンが後置されているcdについては,引数有りオプションとなります.

オプションが残らないように,サブシェルで実行するなどしてください.

tmpファイルの作成

tmpファイルの作成にはmktempコマンドを使います.

tmp_file=$(mktemp)  #一時的に利用するファイル
tmp_dir=$(mktemp -d) #一時的に利用するフォルダ

必要な処理を行なった後,最後に

trap "
rm -f $tmp_file
rm -rf $tmp_dir
" 0

とすれば,不要な一時ファイルを削除することができます.

スペース区切りされる結果の利用

コマンドの実行結果がある種の順序を持ったスペース区切りで列挙される場合,次のようにsetコマンドを利用して引数を変数に格納することができます.

set -- `date '+%Y %m %d'`
year="$1"
month="$2"
day="$3"

小数点を含んだ計算

計算はbcで行います.

echo 計算式 | bc

書式をprintfで指定することで,小数点第1位までで四捨五入して出力を行います.

printf '%.1f \n' `echo '計算式' | bc -l`

関連して,単位換算について調べたいときはunitsコマンドを使うとよいでしょう.
pointからmmに換算する比率を調べる例は,

units
You have: point
You want: mm
* 0.35277778
/ 2.8346457

です.
最後の2行が出力結果で,pointの値に0.35277778を掛けるか,mmを2.8346457で割ればよいことを意味しています.

キーボード入力の読み込み

キーボード入力を変数に格納するには,

read 変数名(複数可)

とします.
同じ要領で,readだけ書いておけば,キー入力するまで一時停止できます.

スクリプトのあるディレクトリを取得する

実行しているスクリプトが存在するディレクトリまでのパス取得は

path=$(dirname $(readlink -f $0))

で行えます.

参考文献

シェルスクリプトを作成するのに必要となる基本的コマンドから文法まで扱った,読めるリファレンスです.

  • 山森丈範 (2017)「シェルスクリプト基本リファレンス」3版,技術評論社.