【Linux】ShellScriptの基本文法 (変数, 日付, 演算, 条件分岐, ループ処理)

ShellScript

こんにちはフロントエンドエンジニアのまさにょんです!

今回は、ShellScriptの基本文法 (変数, 日付, 演算, 条件分岐, ループ処理)についてまとめて解説していきます。

ShellScriptの基本文法まとめ (変数, 日付, 演算, 条件分岐, ループ処理など)

ShellScriptファイルの実行

ShellScriptファイルの実行方法は、絶対パス or 相対パス で ShellScriptファイルにアクセスするだけです。

作業ディレクトリで、次の一文だけの sample.sh ファイルを作成します。

ちなみに、拡張子shは、ShellScriptのファイルであることを示します。

echo 'Hello Robotama'

作成した sample.sh ファイルを実行する場合は、次のようにします。

# 相対パスで指定して、ShellScriptファイルを実行する
./sample.sh

ShellScriptファイルの実行権限を解放する

ShellScriptファイルを実行しようとして、次のようなエラーがでる場合は、Permission設定を変える必要があります。

zsh: permission denied: ./sample.sh

実行権限だけの解放は、次のようにすればOKです。

chmod +x sample.sh

Permission設定に関する細かい説明は、以前の記事にて解説しています。

標準出力

Linuxコマンド、ShellScript での標準出力には、echoコマンドを使用します。

echo 'Hello World'
# Hello World

echo コマンドに関する細かい使い方は、以前の記事にて解説しています。

変数にデータを格納する & 変数を展開する

変数にデータを格納する際は 、変数名=値 と記述します。

「 = 」の前後にスペースを入れてはいけないので注意です。

変数を展開・使用する際は、$変数名“$変数名”“${変数名}”とします。

また、ダブル・クオーテーションではなく、シングル・クオーテーションにすると変数展開ができないので注意です。

## 1. 変数にデータを格納する => 「 = 」の前後にスペースを入れてはいけない
robotama="ロボ玉"

## 2. 変数からデータを取り出す
echo $robotama
# ロボ玉

echo "$robotama"
# ロボ玉

echo "${robotama}"
# ロボ玉

## 3. 変数の中身ではなく文字列として表示されてしまうので注意!
echo '$robotama'
# $robotama

バック・クオーテーションは、コマンドが実行できる

シングル・クオーテーションは、すべてを文字列として取り扱い、ダブル・クオーテーションは、変数だけは展開してくれます。

コマンドを展開・実行してもらいたい時は、バック・クオーテーションを使用すると変数およびコマンドを展開・実行してくれます。

robotama=ロボ玉

# 1. シングル・クオーテーションは、すべてを文字列として取り扱う!
echo 'echo $robotama'

# 2. ダブル・クオーテーションは、変数だけは展開する!
echo "echo $robotama"

# 3. バック・クオーテーションは、変数を展開するだけでなく、コマンドも実行できる!
echo `echo $robotama`

### 実行結果 ###
# echo $robotama
# echo ロボ玉
# ロボ玉

定数の定義

定数(読み取り専用)を定義する場合は、readonly を変数名の前に付与します。

## 1. 定数(読み取り専用)を定義する
readonly gunmar='神聖グンマー帝国'

echo ${gunmar}
# 神聖グンマー帝国

## 2. 定数なので、再代入しようとするとエラーがでる
gunmar=ゴンさん
# [エラー] gunmar: readonly variable

文字列の連結

文字列の連結には、「 + 」などの記号は必要ありません。

ただ、並べるだけで連結されます。

echo 'ゴンさん'
# ゴンさん

## 1. 文字列の連結
echo 'Hunter'' × ''Hunter'
# Hunter × Hunter

robotama="ロボ玉"
echo $robotama' × '$robotama
# ロボ玉 × ロボ玉

echo "$robotama And $robotama"
# ロボ玉 And ロボ玉

echo "${robotama}は、グンマー帝国出身です"
# ロボ玉は、グンマー帝国出身です

四則演算

expr コマンドによる計算は書き方が面倒なので、数値計算には、 $(( … )) を使用するのがオススメです。

ちなみに似たような機能で let コマンドや ((…)) がありますが、どの環境でも使えるのは $((…)) だけです。

bash だけではなく、すべての POSIX 準拠のシェルで使うことができる点で考えても、 $(( … )) を使った方がよさそうです。

x=10

## 1. 通常、数値を格納しても文字列として取り扱われる。
echo $x+2
# 10+2

## 2. 数値を計算する場合は、$((計算式))と記述する
echo $(($x+2))
# 12

echo $((($x+5) * 2))
# 30

配列の取り扱い

ShellScriptでは、()と半角スペースで配列を定義します。

配列の中の特定の要素を取り出すには、${配列名[index]} で取り出します。

配列の中身をすべて取り出すには、${配列名[@]} とします。

また、${#配列名[@]} で、配列の長さ・要素数を取得することができます。

### 配列の定義 ###

## 1. ()と半角スペースで配列を定義する
array=(2 4 6)

### 配列のデータを取得する ###

## 2. 配列名だけで変数展開すると最初の要素が表示される
echo $array
# 2

## 3. 指定して中身を取り出すには、${配列名[index]} で取り出す
echo ${array[0]}
# 2

## 3. 指定して中身を取り出すには、${配列名[index]} で取り出す
echo ${array[1]}
# 4

# 4. ${} で変数展開しないと、最初の要素と文字列を連結した文字列になる・・・
echo $array[1]
# 2[1]

## 5. 配列の中身をすべて取り出すには、${配列名[@]} とする
echo ${array[@]}
# 2 4 6

## 6. ${#配列名[@]} で、配列の長さ・要素数を取得することができる
echo ${#array[@]}
# 3

### 配列にデータを追加する ###

## 7. 配列の指定Indexに値を代入する
array[2]=10 
echo ${array[@]}
# 2 4 10

## 7. 配列の指定Indexに値を代入する
array[3]=20
echo ${array[@]}
# 2 4 10 20

## 8. 配列に値を、まとめて追加する
array+=(30 40)
echo ${array[@]}
# 2 4 10 20 30 40

日付・時間の操作

Linuxでの日付・時間の操作は、dateコマンドを使います。

ちなみに、Macのdateコマンドは、使い方が違うので注意です。詳細は、次の記事を参照。

【備忘録】macのdateコマンド(BSD系)で日付を出力、計算する

##### 日付の取得・操作 #####

# 1. 今日の日時情報
date
# 2023年 1月12日 木曜日 07時40分28秒 JST

# 2. `date`は日付や曜日を要素とした配列になっている。
d=(`date`)

echo $d
# 2023年 1月12日 木曜日 07時40分28秒 JST

echo ${d[@]}
# 2023年 1月12日 木曜日 07時40分28秒 JST

# 3. ループで取り出す。
for i in ${d[@]}
do
    echo $i
done
## 出力結果 ##
# 2023年
# 1月12日
# 木曜日
# 07時26分30秒
# JST


### 過去・未来の日時を取得する ###

# 2日前の日付を取得する
date -d '2 days ago'

# 現在の月を取得する
date '+%m'
# 10

# Nヶ月前の月を取得する
date -d "`date '+%Y-%m-01'` 1 months ago" '+%m'

# 現在日時から10秒前の日時を求める
date -d '10 seconds ago'

# 現在日時から10秒後の日時を求める
date -d '10 seconds'

# 現在日時から10分前の日時を求める
date -d '10 minutes ago'

# 現在日時から10分後の日時を求める
date -d '10 minutes'

# 現在日時から10時間前の日時を求める
date -d '10 hours ago'

# 現在日時から10時間後の日時を求める
date -d '10 hours'

# 現在日時から10日前の日時を求める
date -d '10 days ago'

# 現在日時から10日後の日時を求める
date -d '10 days'

# 現在日時から10ヶ月前の日時を求める
date -d '10 months ago'

# 現在日時から10ヶ月後の日時を求める
date -d '10 months'

# 現在日時から10年前の日時を求める
date -d '10 years ago'

# 現在日時から10年後の日時を求める
date -d '10 years'


### 日付のフォーマットを指定して実行する ###
# 上記のコマンドはそれぞれフォーマットを指定して実行することも可能

date -d '12 hours ago' '+%Y-%m-%d [%H:%M:%S]'

### 指定した日時で実行する ###

# date コマンドで表示される日時を現在日時ではなく、
# 次のように指定した日時で date コマンドを実行することも可能である。

# 現在日時を「2006/01/01 12:13:14」としてコマンドを実行する
date -d '2006/01/01 12:13:14'

# フォーマットの指定も可能
date -d '2006/01/01 12:13:14' '+%Y %m %d - %H %M %S'

条件式の評価の基本ルール

  1. 正常終了は0が返ってくる。異常終了は1が返ってくる。
  2. testコマンドで条件式を評価できる(testコマンドは[]で置き換え可能)
  3. $?で、直前に終了した命令が正常終了したかどうかを評価できる

数値の比較演算子

  • -eq : equal
  • -ne : not equal
  • -gt : greater than (◯◯より大きい)
  • -ge : greater than or equal (◯◯以上)
  • -lt : less than (◯◯より小さい)
  • -le : less than or equal (◯◯以下)
## 比較演算子 ##

# 1. testコマンド or [ ] で、条件式を記述する

# 2. $? => 0は正常(true)/1は異常(false)

test 1 -eq 2
echo $?
# 1

# testコマンドではなく、[] を使っても条件式を記述することができる。
[ 1 -eq 2 ]
echo $?
# 1

test 1 -eq 1
echo $?
# 0 

# 「 ; 」区切りで、インラインで(1行で)実行できる
test 1 -eq 2; echo $?
# 1

test 1 -eq 1; echo $? 
# 0 

文字列の比較演算子

  • = : equal
  • != : not equal
[ robotama = robotama ]
echo $?
# 0

[ robotama != robotama ]
echo $?
# 1

ファイルの比較演算子

  • -nt : newer than(より新しいかどうか)
  • -ot : older than(より古いかどうか)
  • -e : exist (存在しているかどうか)
  • -d : directory (ディレクトリかどうか)
ShellScript-関連 % ls -l
total 40
-rwxr-xr-x    1 robotama  staff   270  1  9 16:14 Gunmar.sh
-rwxr-xr-x    1 robotama  staff   429  1 12 07:54 Puru.sh
-rwxrwxrwx    1 robotama  staff  6246  1 12 08:00 robotama.sh
-rwxrwxrwx    1 robotama  staff     2  1 12 22:25 sample.sh
test Gunmar.sh -nt robotama.sh; echo $?
# 1

test Gunmar.sh -ot Puru.sh; echo $?
# 0

test -e Gunmar.sh; echo $?
# 0

[ -d Puru.sh ]; echo $?
# 1

論理演算子

  • -a : and
  • -o : or
  • ! : is not
# ファイルが存在するかどうか
test -e hello.sh -o -e Gunmar.sh; echo $?
# 1

# 1 = 1 && 2 == 2 
test 1 -eq 1 -a 2 -eq 2; echo $?
# 0

# 5 != 5
test ! 5 -eq 5; echo $?
# 1

条件分岐・if文

### 条件分岐・if文 ###

x=21

if [ $x -ge 60 ]
    then
    echo "60以上の数値 (greater than or equal 60 : 60以上)"
elif [ $x -ge 40 ]
    then
    echo "40以上の数値 (greater than or equal 40 : 40以上)"
elif [ $x -ge 20 ]
    then
    echo "20以上の数値 (greater than or equal 20 : 20以上)"
else 
    echo "19以下の数値"
fi 
    echo "必ず呼び出される finally処理"


## 実行結果 ##
# 20以上の数値 (greater than or equal 20 : 20以上)
# 必ず呼び出される finally処理

条件分岐・case文

  1. caseの値に合致したときに処理は ) から ;; まで実行する
  2. 何にも当てはまらない時の条件は *) で指定する
signal="red"
case $signal in
 "red")
  echo "stop!"
  ;;
 "yellow")
  echo "caution!"
  ;;
 "green")
  echo "go!"
  ;;
 *)
  echo "..."
  ;;
esac

## 実行結果 ##
# stop!

while文

条件式の間だけdoとdoneの間の処理をする。

i=0
while [ $i -lt 12 ]
do
    i=`expr $i + 1`
    echo $i
done

continue文・break文

i=0

# :を使うと常に0(正常終了)を返すので、無限ループになる
while :
do
    i=$(($i + 1))

    # 3 <= $i <= 10 の時は、何も処理せずにループ続行する
    if [ $i -ge 3 -a $i -le 10 ]; then
        continue
    fi

    # $iが13以上になったらループ終了
    if [ $i -ge 13 ]; then
        break
    fi  
    echo $i
done

## 実行結果 ##
# 1
# 2
# 11
# 12

for文

inに続くスペース区切りの値を入れていきdoとdoneの間の処理を実行

for i in 1 2 3 4 5
do
    echo $i
done

# 配列を使いたい時
a=(1 2 3 4 5)
for i in ${a[@]}
do
    echo $i
done
# continue文・break文の使い方は、while文と同様
numList=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
for i in ${numList[@]}
do
    if [ $i -ge 3 -a $i -le 10 ]; then
        continue
    fi

    # $iが13以上になったらループ終了
    if [ $i -ge 13 ]; then
        break
    fi  
    echo $i
done

コマンド引数の使い方

sample.shファイルを次の内容で作成する

# ファイル名
echo $0 

# 1番目の引数
echo $1

# 2番めの引数
echo $2 

# 全ての引数
echo $@ 

# 引数の数
echo $# 

./sample.sh フィルに引数を渡して、実行する

# 1. sample.shファイルに3つ引数を渡して、実行する
./sample.sh robotama purupuru nanoda

### 実行結果 ###
./sample.sh
robotama
purupuru
robotama purupuru nanoda
3

ユーザーからの入力を受け付る

readコマンドを使って、ユーザーが入力した値を変数に格納できます。

入力 & Enterを待機するので、入力内容に応じた処理ができます。

keyという変数にユーザーの入力した値を入れて処理しています。

# 「 while : 」は永続true => 無限ループ
while : 
do
    # readコマンドを使って、ユーザーが入力した情報を変数に格納する => 入力 & Enterを待機する
    read key
    echo "you pressed $key"

    # 「 end 」と入力した時だけ、終了する(無限ループから抜け出す)
    if [ $key = "end" ]; then
        break
    fi
done

sample.sh ファイルを実行して、入力 & Enterを繰り返す。

./sample.sh
robotama
you pressed robotama
purupuru
you pressed purupuru
gunmar
you pressed gunmar
end
you pressed end

選択肢(option)から選ばせる

select というコマンドを使用することで、選択肢から選ばせることができる。

select option in Gunma Saitama Tokyo
do
    echo "you from $option"
    break;
done

sample.sh ファイルを実行して、Gunmaを選択する。

./sample.sh
1) Gunma
2) Saitama
3) Tokyo
#? 1
you from Gunma

ファイルから入力する

ロボ玉試作1号機
ロボ玉試作2号機
ロボ玉試作3号機
i=1

# 変数lineに1行ずつ格納される
while read line
do
    echo "$i: $line"
    i=$(($i + 1))

# ここで読み込むファイルを指定(引数)
done < $1
./sample.sh Robotama.txt

## 実行結果 ##
1: ロボ玉試作1号機
2: ロボ玉試作2号機
3: ロボ玉試作3号機

関数の作成

関数内で作った変数は関数外でも使用できる。ローカル変数にしたい場合は local i=12 みたいにlocalを使用する。

# functionは省略可能
function JoJo () {

    echo "$1・$2、みんな JoJoって呼ぶんだ"

    i=12
    echo "好きな数字は${i}"
}

# 関数を実行する
JoJo ジョニー ジョコビッチ

## 実行結果 ##
ジョニー・ジョコビッチ、みんな JoJoって呼ぶんだ
好きな数字は12

関連記事

プログラミング学習・エンジニア転職関連の情報

自宅で現役エンジニアから学べる『TechAcademy』 (エンジニア転職保証)

『GEEK JOBキャンプ』スピード転職コース(無料)

【IT道場】入校時0円! 就職目的プログラミングスクール

エンジニア転職なら100%「自社開発」求人に強い【クラウドリンク】

『techgym』 (Python特化・無料)

Twitterやってます!Follow Me!

神聖グンマー帝国の逆襲🔥

神聖グンマー帝国の科学は、世界一ぃぃぃぃぃぃ!!!!!

Linux関連書籍

参考・引用

  1. シェルスクリプトの基礎知識まとめ
  2. 今どきのシェルスクリプトは数値計算にexprを使わない(POSIX準拠)
  3. 日付を取得する | UNIX & Linux コマンド・シェルスクリプトリファレンス
  4. 【Linux】echoコマンドの使用方法

最近の投稿