こんにちは。インフラエンジニアをしていますknmriiです。
今回はbashのシェルスクリプトについて、基本的な書き方やよく使うコマンドなどを紹介していきます。
bashでのプログラミングを学び始めた方や、インフラエンジニアになりたての方のご参考になりましたら幸いです。
また、普段は別の言語に触れられている方についてもサーバサイドではこのようなbashのスクリプトが動いていることが多いですので
参考までに一読していただければと思います。
目次
bash・シェルスクリプトとは
そもそもbash シェルスクリプトとは何ぞやという話からさせて頂きます。
bashとは、多くのUNIX系OSで標準的に用いられるシェルプログラムの一つ。標準の実行プログラムファイル名(コマンド名)は「bash」だが、「sh」が指定された場合も起動するようシンボリックリンクが置かれることが多い。
シェルスクリプトとは、OS(オペレーティングシステム)を操作するためのシェル上で実行できる簡易なプログラミング言語(スクリプト言語)。また、そのような言語によって書かれた、複数のOSコマンドや制御文などを組み合わせた簡易なプログラム。一般的にはUNIX系OSのシェルで実行できるものを指す。
調べてみたところ上記のような解説がありましたが、入門者にとってはかなり難しく感じると思いますので簡単に言い換えてみるとこのようになります。
bash → Unix系(Linux含む)のOSでユーザがコマンドを入力し、それに応じてシステムが処理をしたり応答を返すための仲介をするプログラム(シェル)の一種。
シェルスクリプト → コマンドを組み合わせた簡易的なプログラミング言語。
bashを用いたシェルスクリプトの書き方
ここからは実際のbashを用いたシェルスクリプトの書き方を紹介します。
シバン シェバング(Shebang)
シェルスクリプトの1行目によく記載されている以下のようなものをシバン シェバング(Shebang)と呼びます。
実行するシェルスクリプトのインタプリタを指定しています。
シバンを以下のように記載することで、シェルスクリプトがbashを使用して実行されるようになります。
ついつい忘れがちな1行かもしれませんが、bashにしかない機能を使用したい場合に、この記載がないと意図したように動かない可能性があります。
bashを用いたシェルスクリプトを作成する際には必ず書くようにしましょう。
#!/bin/bash
また、記載するパスを#!/bin/sh
としても大抵の場合/bin/sh
は/bin/bash
のシンボリックリンクとなっているため、動作はしますが一部挙動が変化するようです。
#!/bin/sh
参考:「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 /bin/sh
コメント
bashのスクリプト内にコメントを残したい場合には、行の先頭に#
を付けましょう。
#!/bin/bash # echo "bashでこの行はコメントです" echo "bashでこの行はコメントではありません"
〇実行結果
bashでこの行はコメントではありません
変数の定義
bashでの変数は変数名
と値
を=
でつなげることで定義することができます。
一般的には、変数と定義する際に初期値の代入をすることが多いです。
この際に、javaでいうint
やString
のような型を指定する必要はありません。
ただし、基本的にbashでは変数に代入された値の全てが文字列として扱われます。
また、=
の前後にスペースを入れるとエラーとなりますのでご注意ください。
変数の内容はecho $変数
とすることで出力することができます。
変数に値を代入する
bashでは変数と値を=
で接続するだけで代入が可能です。
#!/bin/bash NUM=8 MESSAGE=Hello_bash echo $NUM echo $MESSAGE
〇実行結果
8
Hello_bash
変数にスペース等が入った文字列を代入する
bashでは、ダブルクオーテーションで値を囲むとスペースが入った文字列も変数に代入することが可能です。
#!/bin/bash MESSAGE="Hello bash"
〇実行結果
Hello bash
<注意点>
スペースが入った文字列をダブルクオーテーションで囲まずに代入すると、bashのルール的にスペース以降の文字列が別コマンドとして認識されてしまいます。
変数にコマンドの実行結果を代入する
bashにてコマンドの実行結果を変数に代入したい場面が非常に多いです。
そのような場合は、バッククオートでコマンドを囲みます。
#!/bin/bash HOSTNAME=`hostname` echo $HOSTNAME
testhost001
スクリプト実行時の引数を変数に代入する
bashのスクリプトを実行する際、引数を渡すことができます。
一般的な引数は、一度変数に格納してスクリプト内で使用することが多いです。
また、引数は${1}
${2}
のように、渡した順番を指定して呼び出すことも可能です。
#!/bin/bash NUM=${1} STRING=${2} echo "引数1は${NUM}です" echo "引数2は${STRING}です"
〇実行結果
$ sh test.sh 1 bash 引数1は1です 引数2はbashです
配列の定義
bashにて配列の定義をする場合は、変数と同様に配列名
と配列
を=
でつなげます。
この際、配列に関しては(A B C)
のようにかっこで囲み値ごとにスペースを入れます。
#!/bin/bash ARRAY=(0 1 2 3 4 5)
bashで配列の中身を参照するには、以下のようにします。
先頭の内容を参照する
#!/bin/bash ARRAY=(0 1 2 3 4 5) echo $ARRAY
〇実行結果
0
任意の配列番号の内容の参照する
#!/bin/bash ARRAY=(0 1 2 3 4 5) echo "${ARRAY[1]}"
〇実行結果
1
配列の内容を全て参照する
#!/bin/bash ARRAY=(0 1 2 3 4 5) echo "${ARRAY[@]}"
〇実行結果
0 1 2 3 4 5
for文
指定回数を繰り返したい場合
bashでのfor文は以下のようにします。
seq
コマンドを使用することで指定の回数を繰り返すことが可能です。
#!/bin/bash for i in `seq 0 5` do echo $i done
〇実行結果
0 1 2 3 4 5
配列の要素数だけ繰り返したい場合
配列の中身を順番に取り出したいケースはかなり多いと思います。
そのような場合、bashでは以下のようにするとfor文で全て取り出せます。
#!/bin/bash ARRAY=(January February March April May June July August September October November December) for i in ${ARRAY[@]} do echo $i done
〇実行結果
January February March April May June July August September October November December
while文
一般的なwhile文
bashでの一般的なwhile文は以下のように記載できます。
[]
で囲まれている部分については、testコマンドが実行されているのですが、testコマンドについてはif文の項目で解説しようと思います。
#!/bin/bash count=0 while [ $count -lt 5] do count=$((++count)) echo $count done
〇実行結果 test.txt
1 2 3 4 5
readコマンドを使用したwhile文
テキストファイルの全ての行に対して処理をしたいことが度々あります。
そのような場合に使用するのが、readコマンドを使用したwhile文です。
〇サンプルファイル
January February March April May June July August September October November December
#!/bin/bash while read line do echo $line done < test.txt
〇実行結果
January February March April May June July August September October November December
if文
bashで特定の条件で処理を分岐させたい場合には、if文を使用します。
bashでのif文の多くはtestコマンドを使用します。
また、testコマンドを使用したif文はこのように記載します。
if [ 条件1 ]; then 処理1 ## 条件1が真であれば処理1が実行される elif [ 条件2 ]; then 処理2 ## 条件を複数使用したい場合は elif を使用する ## 条件2が真であれば処理2が実行される else 処理3 ## 条件1 2 がどちらでも真でなければ処理3が実行される fi
上記のように []
を使用してその中に条件を記載するのですが、その記載方法はtest
コマンドに準じています。
testコマンドにて使用できるパラメータの一例として、以下のようなものがあります。
項目 | 例 | 説明 |
---|---|---|
-e | [ -e /tmp/testfile ] | testfileが存在していれば真 |
-f | [ -e /tmp/testfile ] | testfile存在していて通常ファイルであれば真 |
-d | [ -d /tmp/testdir] | testdirが存在していてディレクトリであれば真 |
-z | [ -z 文字列 ] | 文字列の長さが0であれば真 |
-n | [ -n 文字列 ] | 文字列の長さが0でなければ真 |
-eq | [ 数値1 -eq 数値2 ] | 数値1と数値2が等しければ真(=) |
-ne | [ 数値1 -ne 数値2 ] | 数値1と数値2が等しければ真(!=) |
-gt | [ 数値1 -gt 数値2 ] | 数値1が数値2より大きければ真(>) |
-ge | [ 数値1 -ge 数値2 ] | 数値1が数値2以上であれば真(>=) |
-lt | [ 数値1 -lt 数値2 ] | 数値1が数値2より小さければ真(<) |
-le | [ 数値1 -le 数値2 ] | 数値1が数値2以下であれば真(<=) |
= | [ 文字列1 = 文字列2 ] | 文字列1と文字列2が等しければ真 |
!= | [ 文字列1 != 文字列2 ] | 文字列1と文字列2が等しくなければ真 |
if文の使用例としてのサンプルは以下です。
#!/bin/bash NUMS=(1 2 3 4 5 6 7 8 9 10) STRINGS=(January February March April May June July August September October November December) echo "===========TEST1===========" for num in ${NUMS[@]} do if [ $num -gt 5 ]; then echo "$numは5より大きいです。" else echo "$numは5以下です。" fi done echo "===========TEST2===========" for num in ${NUMS[@]} do if [ $num -le 5 ]; then echo "$numは5以下です。" else echo "$numは5より大きいです。" fi done echo "===========TEST3===========" for str in ${STRINGS[@]} do if [ $str = "January" ];then echo "$str は1月です" touch /tmp/jaunary.txt else echo "$str は1月ではありません。" fi done echo "==========================="
〇実行結果
===========TEST1=========== 1は5以下です。 2は5以下です。 3は5以下です。 4は5以下です。 5は5以下です。 6は5より大きいです。 7は5より大きいです。 8は5より大きいです。 9は5より大きいです。 10は5より大きいです。 ===========TEST2=========== 1は5以下です。 2は5以下です。 3は5以下です。 4は5以下です。 5は5以下です。 6は5より大きいです。 7は5より大きいです。 8は5より大きいです。 9は5より大きいです。 10は5より大きいです。 ===========TEST3=========== January は1月です February は1月ではありません。 March は1月ではありません。 April は1月ではありません。 May は1月ではありません。 June は1月ではありません。 July は1月ではありません。 August は1月ではありません。 September は1月ではありません。 October は1月ではありません。 November は1月ではありません。 December は1月ではありません。 ===========================
case文
bashにて特定の条件で処理を分岐させたい場合には、if文ではなくcase文を使用することもできます。 条件分岐が多い場合はこちらの方が便利ですね。
case 値 in 値1 ) 処理1 ;; 値2 ) 処理2 ;; 値3 ) 処理3 ;; * ) 処理4 # 処理1~3のどれとも一致しなかった場合は処理4が実行される esac
使用例としては以下のような感じです。
#!/bin/bash STRINGS=(January February March April May June July August September October November December) for str in ${STRINGS[@]} do case $str in January ) echo "$str は1月です" ;; February ) echo "$str は2月です" ;; March ) echo "$str は3月です" ;; * ) echo "$str は1~3月ではありません" esac done
〇実行結果
January は1月です February は2月です March は3月です April は1~3月ではありません May は1~3月ではありません June は1~3月ではありません July は1~3月ではありません August は1~3月ではありません September は1~3月ではありません October は1~3月ではありません November は1~3月ではありません December は1~3月ではありません
終わりに
今回はbashによるシェルスクリプトの基本的な書き方や、構文についてを紹介しました。
ほかの言語を学習してからbashを使おうとしたり、始めてプログラミングに触れる方にとって戸惑うことも多いかと思いますが、少しでもご参考になれば幸いです。
エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
https://career-recruit.rakus.co.jp/career_engineer/カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.comラクスDevelopers登録フォーム
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!
◆TECH PLAY
techplay.jp
◆connpass
rakus.connpass.com