シェルスクリプト

シェルスクリプトとは

  • シェルスクリプトとは、簡単に言うとUnixコマンドなどを並んで実行するだけです。
  • いつ何の条件で何の命令を実行するとか、ファイルコンテンツを読み込むとか、ログファイルを書き出すとかをする役割です。

基本設定

test.shファイルを作成します。

test.sh
#!/bin/sh

echo "Hello, World!"
  • シェルスクリプトファイルは基本的に.shの拡張子で作成します。
  • 実際のコードを書く前に最初の一行目は #!/bin/shを書き、システムにこれからシェルスクリプトを書きますようと知らせるものです。(#hash!bangですから、#!shebangと言います。)ただし bash の独自機能を使う場合は #!/bin/bash と書かなければなりません (参考: bashコーディング規約“bashism” について思うこと。)
  • シェルスクリプトファイル(test.sh)を実行するには、ターミナルからファイルが保存されてる場所で以下のどちらかのコマンドで実行できます。
$ chmod 755 test.sh
$ ./test.sh
$ sh test.sh
$ bash test.sh

ファイルを実行するとHello, World!が表示されます。

基本コマンド

コメント

#を書いてコメントを書くことができます。

test.sh
#!/bin/sh

# これはコメントです
# echo "コメントは実行されません!"

echo "Hello, World!"

入力・出力

echoで出力、 readで入力します。

test.sh
#!/bin/sh

read NAME
echo "Hello, $NAME!"

実行結果、

$ ./test.sh
Tensai
Hello, Tensai!

入力を待っている時、スクリプトが続きません。
Bash では-eフラグで特殊テキストをエスケープできます。

#!/bin/bash
echo -e "Hello\n$NAME!" #改行されます

変数

  • 変数の名前として半角英数字とアンダーバーが使えます。aからz、AからZ、0から9と_です。
  • 変数に値を与える時=を前後空白なしで書きます。文字列な場合"で囲みます。
  • 変数をアクセスする時変数名の前に$を入れます。あるいは$入れて変数を{}で囲みます。
  • 一つの変数に一つの値しか保存できません。
  • 変数の値を上書きされないようにはreadonlyを使います。
  • 変数をunsetで削除することができます。(readonly変数を削除することができません。)
test.sh
#!/bin/sh

var="これは変数です"
VaR_2="これも変数です"
echo "Var_2=$VaR_2"

VaR_2="VaR_2が変更されました。"
echo ${VaR_2}

readonly var
var="readonly varを変えてみる。"

実行結果、

$ ./test.sh
Var_2=これも変数です
VaR_2が変更されました。
shell.sh: line 11: var: readonly variable

特別な変数

シェルスクリプトでは以下の特別な変数があります。

変数 機能
$0 スクリプト名
$1 ~ $9 引数、1番目の引数を$1、2番目の引数を$2でアクセスする
$# スクリプトに与えた引数の数
$* 全部の引数をまとめて1つとして処理
$@ 全部の引数を個別として処理
$? 直前実行したコマンドの終了値(0は成功、1は失敗)
$$ このシェルスクリプトのプロセスID
$! 最後に実行したバックグラウンドプロセスID
test.sh
#!/bin/sh

echo "\$0(スクリプト名): $0"
echo "\$1(1番目の引数): $1"
echo "\$2(2番目の引数): $2"
echo "\$#(引数の数): $#"
echo "\"\$*\": \"$*\""
echo "\"\$@\": \"$@\""
VAR="exit値は0になるはずです"
echo $?

実行結果、

$ ./test.sh first second 3rd
$0(スクリプト名): test.sh
$1(1番目の引数): first
$2(2番目の引数): second
$3(3番目の引数): 3rd
$#(引数の数): 3
"$*": "first second third"
"$@": "first second third"
0

特殊文字

* ? [ ' " ` \ $ ; & ( ) | ~ < > # % = スペース タブ 改行 はシェルスクリプトの特殊文字です。文字列として使うときは \ を書いてから使います。

変数値の置換

文法 説明
${var} 変数値を入り変えます
${var:-word} 変数がまだセットされていないか空文字列の場合wordを返します。varに保存しません
${var:=word} 変数がまだセットされていないか空文字列の場合wordを返します。varに保存します
${var:?word} 変数がまだセットされていないか空文字列の場合置換に失敗し、スタンダードエラーにエラーを表示します
${var:+word} 変数がセットされている場合wordを返します。varに保存しません
test.sh
#!/bin/sh

echo "1 - ${var:-wordSetInEcho1}"
echo "2 - var = ${var}"
echo "3 - ${var:=wordSetInEcho3}"
echo "4 - var = ${var}"
unset var
echo "5 - ${var:+wordSetInEcho5}"
echo "6 - var = $var"
var="newVarValue"
echo "7 - ${var:+wordSetInEcho7}"
echo "8 - var = $var"
echo "9 - ${var:?StandardErrorMessage}"
echo "10 - var = ${var}"

実行結果:

1 - wordSetInEcho1
2 - var = 
3 - wordSetInEcho3
4 - var = wordSetInEcho3
5 - 
6 - var = 
7 - wordSetInEcho7
8 - var = newVarValue
9 - newVarValue
10 - var = newVarValue

配列 (Bash)

test.sh
#!/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[@]}"

実行結果、

$ ./test.sh
ARRAY[0]: ITEM1
ARRAY[1]: item2
ARRAY[*]: ITEM1 item2 ITEM3 item4
ARRAY[@]: ITEM1 item2 ITEM3 item4

オペレータ

shellでは算術演算子を`expr 数字 演算子 数字`で計算できます。

演算子 意味
+ echo `expr 10 + 20` => 30
echo `expr 20 - 10` => 10
\* echo `expr 11 \* 11` => 121
/ echo `expr 10 / 2` => 5
% 剰余 echo `expr 10 % 4` => 2
= 指定 a=$b bの値はaに保存されます
== [ “$a” == “$b” ] $aと$bが同じ場合TRUEを返します。
!= [ “$a” != “$b” ] $aと$bが同じではない場合TRUEを返します。
比較 意味
-eq イコール [ "$a" -eq "$b" ] $aと$bが同じ場合TRUEを返します。
-ne 異なる [ "$a" -ne "$b" ] $aと$bが違い場合TRUEを返します。
-gt より大きい [ "$a" -gt "$b" ] $aが $bより大きい場合TRUEを返します。
-lt より小さい [ "$a" -lt "$b" ] $aが $bより小さい場合TRUEを返します。
-ge より大きいか同じか [ "$a" -ge "$b" ] $aが $bより大きいか同じ場合TRUEを返します。
-le より小さいか同じか [ "$a" -le "$b" ] $aが $bより小さいか同じ場合TRUEを返します。
! ではない [ ! "$a" -gt "$b" ] $aが $bより大きくない場合TRUEを返します。
-o どちらか [ "$a" -gt "$b" -o "$a" -lt "$b" ] $aが $bより大きいか小さいかの場合TRUEを返します。 (Bash拡張・POSIX廃止予定)
-a 両方 [ "$a" -gt 90 -a "$a" -lt 100 ] $aが 90より大きく100より小さい場合TRUEを返します。 (Bash拡張・POSIX廃止予定)
-z 文字列が空か [ -z "$a" ] $aが何も指定してない場合TRUEを返します
-n 文字列が空か [ -n "$a" ] $aに何かを指定しした場合TRUEを返します

[ コマンドの引数に変数を指定するときは " でクォートする必要があります

上記のオペレータを使ってif条件を書きます。

if 条件

  • ifの基本の書き方は if [ 条件 ] then コマンド fi です。
  • 条件が真の場合 then の次のコマンドを実行します。
  • 違う場合次々の elif [ 条件 ] を確認します。
  • 真の条件がない場合 else の次のコマンドを実行して終了します。
  • else がない場合は、そのまま終了します。
test.sh
#!/bin/sh

if [ "$1" -gt "$2" ]
then 
    echo "1番目の引数が2番目の引数より大きい"
elif [ "$1" -eq "$2" ]
then
    echo "1番目の引数と2番目の引数は同じです"
else
    echo "1番目の引数が2番目の引数より小さい"
fi

実行結果、

$ ./test.sh 2 7
1番目の引数が2番目の引数より小さい
$ ./test.sh 10 5
1番目の引数が2番目の引数より大きい
$ ./test.sh 9 9
1番目の引数と2番目の引数は同じです

Switch 条件

  • switchの基本の書き方は case 変数 in 条件・値) コマンド ;; esac です。
  • 条件・値が変数と合う場合それの次のコマンドを実行します。
test.sh
#!/bin/sh

DRINK="coffee"
case "$DRINK" in
    "beer") echo "ビールです" 
    ;;
    "juice") echo "ジュースです" 
    ;;
    "coffee") echo "プログラマーが飲むとコードに変化!" 
    ;;
esac

実行結果、

$ ./test.sh
プログラマーが飲むとコードに変化!

ループ

ループを、
– breakキーワードで終了
– continueキーワードで現在のループを飛ばすことができます。
ことができます。

while ループ

条件が合うときループします。

test.sh
#!/bin/sh

a=0
while [ $a -lt 5 ]
do
    echo $a
    a=`expr $a + 1`
done

実行結果:

$ ./test.sh
0
1
2
3
4

until ループ

whileの逆で、条件が合うまでループします。

test.sh
#!/bin/sh

a=0
until [ ! $a -lt 5 ]
do
    echo $a
    a=`expr $a + 1`
done

実行結果:

$ ./test.sh
0
1
2
3
4

for ループ

  • forの基本の書き方は for 変数 in 複数値・変数・範囲 do コマンド done です。
  • 条件・値が変数と合う場合それの次のコマンドを実行します。
test.sh
#!/bin/sh

for var in 0 1 2 3 4  #範囲の書き方(Bash独自) => {0..4}
do
    echo $var
done

実行結果:

$ ./test.sh
0
1
2
3
4

関数

シェルスクリプトでは、関数を書いて引用することができます。

test.sh
#!/bin/sh

#関数を指定します
MyFunction () { 
    echo "関数のechoです。"
}
MyParamFunc() {
    echo "引数1:$1 引数2:$2"
}

#関数を呼び出します
MyFunction
MyParamFunc param1 param2

実行結果:

$ ./test.sh
関数のechoです。
引数1:param1 引数2:param2

おしまい

以上はシェルスクリプトの基本コマンドですが、それをunixコマンドと一緒に使えば効率的になります。unixコマンドも沢山ありますが、以下のサンプルにはファイル移動するコマンドmvexprだけを使っています。

rename.sh
#!/bin/sh

#このスクリプトがあるディレクトリ中の
#txtファイルを全部mytxt{番号}.txtに
#変更するスクリプトです

index=1
for file in *.txt
do
    mv "$file" "mytxt${index}.txt"
    index=`expr $index + 1`
done

実行結果:
lsは現在いるディレクトリ中のファイルをリストします。

$ ls
aaa.txt     bbb.txt     ccc.txt     ddd.txt     eee.txt     test.sh
$ ./test.sh
$ ls
mytxt1.txt  mytxt2.txt  mytxt3.txt  mytxt4.txt  mytxt5.txt  test.sh

今日は以上になります。