1. 👋 はじめに
前回まででLinuxの基本コマンドをひととおり学びました。
今回はシェルスクリプトを使って、複数のコマンドをまとめて自動実行する方法を解説します!
🙋 シェルスクリプトを使うと…
毎日やっていた作業:
1. ログファイルを圧縮する
2. 古いファイルを削除する
3. バックアップをコピーする
4. 完了メッセージを表示する
↓
スクリプト1つで全部自動化!🎉
この記事を読めば:
- ✅ シェルスクリプトの基本構文がわかる
- ✅ 変数・条件分岐・ループが使える
- ✅ 実用的なスクリプトが書ける
2. 📄 シェルスクリプトとは?
シェルスクリプトは、シェル(bashやzsh など)のコマンドをファイルにまとめたものです。
# これが最もシンプルなシェルスクリプト
echo "Hello, World!"
ls -la
mkdir backup
これをファイルに書いて実行するだけで、3つのコマンドが順番に実行されます!
スクリプトファイルの作り方
# 1️⃣ ファイルを作成
touch hello.sh
# 2️⃣ 内容を書く(例:echo "Hello, World!")
vim hello.sh
# 3️⃣ 実行権限を付与(第二回で学びましたね!)
chmod +x hello.sh
# 4️⃣ 実行する
./hello.sh
シバン(shebang):必ず1行目に書く
#!/bin/bash
# ↑ これがシバン(shebang)
# 「このスクリプトをbashで実行してください」という宣言
echo "Hello, World!"
#! で始まる1行目をシバンと呼びます。どのシェルで実行するかをOSに伝えます。
#!/bin/bash → bash で実行
#!/bin/sh → sh で実行(より互換性が高い)
#!/usr/bin/env bash → 環境に合わせてbashを探して実行(推奨)
コメントの書き方
#!/bin/bash
# これはコメントです(#から行末まで無視される)
echo "Hello!" # 行末コメントもOK
# コメントを使って
# スクリプトの目的や処理内容を書いておくと
# 後で読み返したときにわかりやすい!
3. 📦 変数
変数の基本
#!/bin/bash
# 変数に値を代入(= の前後にスペースを入れない!)
NAME="Alice"
AGE=25
TODAY=$(date +%Y-%m-%d) # コマンドの結果を変数に代入
# 変数を使う($ をつける)
echo "名前:${NAME}"
echo "年齢:${AGE}"
echo "今日:${TODAY}"
⚠️ よくあるミス
NAME = "Alice" # ← = の前後にスペースがあるとエラー!
NAME="Alice" # ← これが正しい
変数の種類
# ローカル変数(そのスクリプト内だけで使える)
MY_NAME="Alice"
# 環境変数(子プロセスにも引き継がれる)
export DATABASE_URL="postgresql://localhost/mydb"
# 読み取り専用変数(変更できない)
readonly MAX_RETRY=3
# よく使う組み込み変数
echo $HOME # ホームディレクトリ
echo $USER # 現在のユーザー名
echo $PATH # コマンドの検索パス
echo $PWD # 現在のディレクトリ
echo $$ # 現在のプロセスID
特殊変数(引数を受け取る)
スクリプトに引数を渡すことができます。
#!/bin/bash
# greet.sh
echo "スクリプト名:$0"
echo "第1引数:$1"
echo "第2引数:$2"
echo "引数の数:$#"
echo "全引数:$@"
# 実行例
./greet.sh Alice 25
# 出力
スクリプト名:./greet.sh
第1引数:Alice
第2引数:25
引数の数:2
全引数:Alice 25
4. 🔢 数値の計算
#!/bin/bash
# (( )) で算術演算
A=10
B=3
echo $((A + B)) # 13
echo $((A - B)) # 7
echo $((A * B)) # 30
echo $((A / B)) # 3(整数除算)
echo $((A % B)) # 1(余り)
# 変数に計算結果を代入
TOTAL=$((A + B))
echo "合計:${TOTAL}"
# インクリメント(1増やす)
COUNT=0
((COUNT++))
echo ${COUNT} # 1
5. 🔀 条件分岐(if文)
基本のif文
#!/bin/bash
AGE=20
if [ ${AGE} -ge 18 ]; then
echo "成人です"
else
echo "未成年です"
fi
比較演算子
数値の比較:
| 演算子 | 意味 | 例 |
|---|---|---|
-eq |
等しい(=) | [ $A -eq $B ] |
-ne |
等しくない(≠) | [ $A -ne $B ] |
-gt |
より大きい(>) | [ $A -gt $B ] |
-ge |
以上 (>=) | [ $A -ge $B ] |
-lt |
より小さい(<) | [ $A -lt $B ] |
-le |
以下 (<=) | [ $A -le $B ] |
文字列の比較:
NAME="Alice"
if [ "${NAME}" = "Alice" ]; then
echo "Aliceです"
fi
if [ "${NAME}" != "Bob" ]; then
echo "Bobではありません"
fi
# 文字列が空かどうか
if [ -z "${NAME}" ]; then
echo "空です"
fi
if [ -n "${NAME}" ]; then
echo "空ではありません"
fi
ファイル・ディレクトリの確認:
FILE="memo.txt"
DIR="backup"
# ファイルが存在するか
if [ -f "${FILE}" ]; then
echo "ファイルが存在します"
fi
# ディレクトリが存在するか
if [ -d "${DIR}" ]; then
echo "ディレクトリが存在します"
fi
# ファイルが空でないか
if [ -s "${FILE}" ]; then
echo "ファイルにデータがあります"
fi
# 実行権限があるか
if [ -x "${FILE}" ]; then
echo "実行できます"
fi
elif・elseで複数条件
#!/bin/bash
SCORE=75
if [ ${SCORE} -ge 90 ]; then
echo "優秀 🌟"
elif [ ${SCORE} -ge 70 ]; then
echo "合格 ✅"
elif [ ${SCORE} -ge 50 ]; then
echo "もう少し 📚"
else
echo "不合格 ❌"
fi
AND・OR条件
#!/bin/bash
AGE=25
SCORE=80
# AND(両方満たす)
if [ ${AGE} -ge 18 ] && [ ${SCORE} -ge 70 ]; then
echo "条件を満たしています"
fi
# OR(どちらか満たす)
if [ ${AGE} -lt 18 ] || [ ${SCORE} -lt 50 ]; then
echo "条件に引っかかりました"
fi
6. 🔁 繰り返し(ループ)
forループ:リストを順番に処理
#!/bin/bash
# リストをループ
for FRUIT in りんご バナナ みかん; do
echo "🍎 ${FRUIT}"
done
# 出力
# 🍎 りんご
# 🍎 バナナ
# 🍎 みかん
# 数値のループ
for i in 1 2 3 4 5; do
echo "${i}回目"
done
# seq を使うと連番を簡単に生成できる
for i in $(seq 1 5); do
echo "${i}回目"
done
# C言語スタイルのループ
for ((i=1; i<=5; i++)); do
echo "${i}回目"
done
# ファイルをループ処理(よく使う!)
for FILE in *.log; do
echo "処理中:${FILE}"
gzip "${FILE}" # ログファイルを圧縮
done
whileループ:条件が真の間ループ
#!/bin/bash
COUNT=1
while [ ${COUNT} -le 5 ]; do
echo "${COUNT}回目"
((COUNT++))
done
# 出力
# 1回目
# 2回目
# 3回目
# 4回目
# 5回目
# ファイルを1行ずつ読み込む
# まず試し用のファイルを作成しておこう!
cat <<EOF > names.txt
Alice
Bob
Charlie
EOF
# 1行ずつ読み込む
while read LINE; do
echo "行:${LINE}"
done < names.txt
# 出力
# 行:Alice
# 行:Bob
# 行:Charlie
breakとcontinue
#!/bin/bash
# break:ループを抜ける
for i in $(seq 1 10); do
if [ ${i} -eq 5 ]; then
echo "5で終了!"
break
fi
echo ${i}
done
# continue:次のループへスキップ
for i in $(seq 1 5); do
if [ ${i} -eq 3 ]; then
echo "3はスキップ"
continue
fi
echo ${i}
done
7. 🔧 関数
処理をまとめて再利用できるようにしたものが関数です。
#!/bin/bash
# 関数の定義
greet() {
local NAME=$1 # local で関数内だけの変数を宣言
echo "こんにちは、${NAME}さん!"
}
# 関数の呼び出し
greet "Alice"
greet "Bob"
# 出力
# こんにちは、Aliceさん!
# こんにちは、Bobさん!
戻り値
#!/bin/bash
# 終了コードで成功・失敗を返す
check_file() {
local FILE=$1
if [ -f "${FILE}" ]; then
return 0 # 成功(true)
else
return 1 # 失敗(false)
fi
}
# 呼び出し側での判定
if check_file "memo.txt"; then
echo "ファイルが見つかりました ✅"
else
echo "ファイルが見つかりません ❌"
fi
8. 🛡️ エラーハンドリング
コマンドの終了コード
# コマンドが成功すると $? に 0 が入る
# 失敗すると 0 以外の値が入る
ls memo.txt
echo "終了コード:$?" # 0(成功)
ls 存在しないファイル
echo "終了コード:$?" # 1 や 2 など(失敗)
set -e:エラーで即終了
#!/bin/bash
set -e # エラーが起きたら即スクリプトを終了
echo "処理1"
ls 存在しないファイル # ← ここでエラー → 即終了!
echo "処理2" # ← 実行されない
set -u:未定義変数をエラーにする
#!/bin/bash
set -u # 未定義の変数を参照したらエラー
echo ${UNDEFINED_VAR} # ← エラーになる(バグを早期発見できる!)
まとめて設定する(推奨)
#!/bin/bash
set -eu # -e と -u を同時に設定
# スクリプトの先頭にこれを書く習慣をつけよう!
9. 🔖 実用的なスクリプト例
例①:バックアップスクリプト
#!/bin/bash
set -eu
# 設定
SOURCE_DIR="/home/alice/documents"
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d)
BACKUP_FILE="${BACKUP_DIR}/backup_${DATE}.tar.gz"
# バックアップディレクトリがなければ作成
if [ ! -d "${BACKUP_DIR}" ]; then
mkdir -p "${BACKUP_DIR}"
echo "📁 バックアップディレクトリを作成しました"
fi
# バックアップを作成
echo "🔄 バックアップを開始します..."
tar -czf "${BACKUP_FILE}" "${SOURCE_DIR}"
# 結果を確認
if [ -f "${BACKUP_FILE}" ]; then
echo "✅ バックアップ完了:${BACKUP_FILE}"
else
echo "❌ バックアップに失敗しました"
exit 1
fi
# 7日以上前のバックアップを削除
find "${BACKUP_DIR}" -name "backup_*.tar.gz" -mtime +7 -delete
echo "🗑️ 古いバックアップを削除しました"
例②:ログ監視スクリプト
#!/bin/bash
set -eu
LOG_FILE="/var/log/app.log"
THRESHOLD=10 # エラーが10件を超えたら警告
# 直近100行のエラー数を数える
ERROR_COUNT=$(tail -n 100 "${LOG_FILE}" | grep -c "ERROR" || true)
echo "エラー件数:${ERROR_COUNT}"
if [ ${ERROR_COUNT} -gt ${THRESHOLD} ]; then
echo "⚠️ 警告:エラーが${THRESHOLD}件を超えました!(${ERROR_COUNT}件)"
exit 1
else
echo "✅ 正常範囲内です"
fi
例③:ユーザーへの確認を求めるスクリプト
#!/bin/bash
echo "ファイルを削除しますか? (y/n)"
read ANSWER
if [ "${ANSWER}" = "y" ] || [ "${ANSWER}" = "Y" ]; then
echo "🗑️ 削除します..."
rm -rf ./temp/
echo "✅ 削除完了!"
else
echo "キャンセルしました"
fi
10. 💡 デバッグのコツ
bash -x:実行内容をトレースする
# スクリプトをデバッグモードで実行
bash -x script.sh
# 出力例(実行されたコマンドが + で表示される)
# + NAME=Alice
# + echo 'こんにちは、Aliceさん!'
# こんにちは、Aliceさん!
echo デバッグ
#!/bin/bash
# 変数の中身を確認したいときは echo を挟む
NAME="Alice"
echo "DEBUG: NAME=${NAME}" # デバッグ用
11. 📋 シェルスクリプト早見表
🔰 基本構造
| 書き方 | 説明 |
|---|---|
#!/bin/bash |
シバン(1行目に必ず書く) |
set -eu |
エラー対策(スクリプト先頭に推奨) |
# コメント |
# から行末まではコメントとして無視される |
📦 変数
| 書き方 | 説明 |
|---|---|
NAME="Alice" |
変数に代入(= 前後にスペースなし!) |
echo ${NAME} |
変数を使う |
TODAY=$(date +%Y-%m-%d) |
コマンドの結果を変数に代入 |
readonly MAX=3 |
読み取り専用変数 |
export VAR="value" |
環境変数として子プロセスにも引き継ぐ |
🔀 条件分岐
if [ 条件 ]; then
処理
elif [ 条件 ]; then
処理
else
処理
fi
🔁 ループ
# forループ
for VAR in リスト; do
処理
done
# whileループ
while [ 条件 ]; do
処理
done
🔧 関数
関数名() {
local 変数=$1 # local で関数内だけの変数を宣言
処理
}
関数名 引数 # 呼び出し
🔢 比較演算子(数値)
| 演算子 | 意味 | 例 |
|---|---|---|
-eq |
等しい | [ $A -eq $B ] |
-ne |
等しくない | [ $A -ne $B ] |
-gt |
より大きい | [ $A -gt $B ] |
-ge |
以上 | [ $A -ge $B ] |
-lt |
より小さい | [ $A -lt $B ] |
-le |
以下 | [ $A -le $B ] |
🔤 比較演算子(文字列)
| 演算子 | 意味 | 例 |
|---|---|---|
= |
等しい | [ "$A" = "$B" ] |
!= |
等しくない | [ "$A" != "$B" ] |
-z |
空文字列である | [ -z "$A" ] |
-n |
空文字列でない | [ -n "$A" ] |
📁 ファイル判定
| 演算子 | 意味 | 例 |
|---|---|---|
-f |
ファイルが存在する | [ -f "memo.txt" ] |
-d |
ディレクトリが存在する | [ -d "backup" ] |
-x |
実行権限がある | [ -x "script.sh" ] |
-s |
ファイルが空でない | [ -s "data.txt" ] |
! |
否定 | [ ! -f "memo.txt" ] |
12. 🎯 まとめ
| 概念 | ポイント |
|---|---|
| 📄 シバン |
#!/bin/bash を1行目に書く |
| 📦 変数 |
NAME="Alice"(=前後スペースなし) |
| 🔀 if文 |
[ ] の中で条件を書く |
| 🔁 forループ | リストや連番を順番に処理 |
| 🔁 whileループ | 条件が真の間繰り返す |
| 🔧 関数 | 処理をまとめて再利用 |
| 🛡️ エラー対策 |
set -eu をスクリプトの先頭に |
シェルスクリプトは「繰り返す作業を自動化する」最強のツールです。最初はシンプルなスクリプトから始めて、少しずつ機能を追加していくのがコツです🌟
これまで3回にわたって学んだLinuxコマンドが、シェルスクリプトの中で活きてきます!ぜひ自分の日常作業を自動化するスクリプトを書いてみてください💪
💬 質問や感想があれば、コメント欄でお気軽にどうぞ!
👍 役に立ったら、いいね&ストックをお願いします!
🎓 ここまで読んでくださって、本当にありがとうございました!
🔗 シリーズ記事
- 【第一回】基本操作 → ファイル操作・検索・エスケープ
- 【第二回】パーミッション・ユーザー管理・テキスト処理
- 【第三回】シェルスクリプト入門(この記事)
- 【番外編】正規表現とsed・awk入門など(近日公開)