「シェルスクリプトって難しそう」と思っていませんか?実際にやってみると、ファイルを1つ作って実行権限を付けるだけで動き始めます。本記事では Ubuntu 24.04 LTS にプリインストールされている bash 5.2.21 を使い、スクリプトの作成から実行・変数・条件分岐・ループ・関数まで、すべて docker run --rm ubuntu:24.04 で実際に動かした出力を載せながら解説します(2026-06-15 実測)。コマンド結果はすべて本物のコンテナの stdout です。
この記事のポイント
- Ubuntu 24.04 LTS には
bash 5.2.21(パッケージ5.2.21-2ubuntu4)がデフォルトで入っており、追加インストール不要 - スクリプトは
#!/bin/bash(シバン行)で始め、chmod +xで実行権限を付与する - 変数・条件分岐(if)・ループ(for/while)・関数の基本構文を実行結果つきで解説
- 終了コード
$?で成否を判定(実測:成功=0、存在しないファイルのls失敗=2) shellcheck 0.9.0がSC2086やSC2045などの落とし穴を実際に検出してくれる
目次
- bashスクリプトとは
- スクリプトの作り方と実行方法
- 変数の使い方
- 条件分岐(if文)の書き方
- ループ(for・while)の書き方
- 関数の定義と呼び出し
- 終了コードとエラー処理
- shellcheckでスクリプトを検証する
- よくあるエラーと解決策
- Ubuntu バージョンによる違い
- まとめ
bashスクリプトとは
bash(バッシュ)は Ubuntu のデフォルトシェルです。シェルとは、入力したコマンドを解釈して OS に渡す「窓口」のプログラムのこと。通常はターミナルで 1 行ずつコマンドを打ちますが、複数のコマンドをファイルにまとめたものが「bashスクリプト」です。
たとえば「毎日ログをバックアップして、古いファイルを削除して、完了を記録する」という一連の作業を 1 つのスクリプトにまとめれば、コマンド 1 つで自動実行できます。VPS でサーバーを運用するなら、この自動化が大きな武器になります。
まず、Ubuntu 24.04 に入っている bash のバージョンを確認してみましょう。以下は docker run --rm ubuntu:24.04 で実際に実行した出力です。

GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
$ echo $BASH_VERSION
5.2.21(1)-release
$ dpkg -l bash | grep ‘^ii’
ii bash 5.2.21-2ubuntu4 amd64 GNU Bourne Again SHell
$ which bash && ls -la $(which bash)
/usr/bin/bash
-rwxr-xr-x 1 root root 1446024 Mar 31 2024 /usr/bin/bash
Ubuntu 24.04 LTS では bash 5.2.21(パッケージ名 5.2.21-2ubuntu4)がプリインストールされていました。バイナリは /usr/bin/bash にあり、約1.4MBです。別途インストールする必要はありません。
スクリプトの作り方と実行方法
①スクリプトファイルを作成する
拡張子は .sh が一般的ですが、必須ではありません。nano や vim などのエディタ、あるいは cat リダイレクトで作成します。今回はコンテナ内で cat > hello.sh を使いました。中身は次の3行です。
echo “Hello, World!”
echo “スクリプト実行成功”
1 行目の #!/bin/bash は「シバン行(shebang)」と呼ばれ、このファイルを bash で実行することを OS に伝えます。必ず先頭行に書いてください。スクリプトの構造をもう少し具体的に示すと、次のようなイメージです。

②実行権限を付与する
作成したファイルはデフォルトでは実行できません。chmod +x で実行権限を付与します。実測では、作成直後の hello.sh は68バイトで、chmod +x 後にパーミッションが -rwxr-xr-x へ変わりました。
$ ls -la hello.sh
-rwxr-xr-x 1 root root 68 Jun 15 02:41 hello.sh
パーミッションの先頭が -rwxr-xr-x になっていれば実行権限が付いています(x が実行を意味します)。
③スクリプトを実行する
実行方法は 2 通りあります。./hello.sh(実行権限を使う)と bash hello.sh(bash に直接読み込ませる)です。どちらも同じ結果になりました。

Hello, World!
スクリプト実行成功
$ bash hello.sh
Hello, World!
スクリプト実行成功
./hello.sh は chmod で付けた実行権限を使って実行します。bash hello.sh は bash に直接読み込ませる方法で、実行権限がなくても動きます。学習用途では bash スクリプト名 が手軽です。実際にターミナルで動かすと、次のような画面になります。

注意
./hello.sh で Permission denied が出た場合は chmod +x hello.sh を実行してください。また、hello.sh とだけ打つと「コマンドが見つからない」エラーになります。必ず ./ を付けるか、bash hello.sh を使ってください(この挙動は後述の「よくあるエラー」で実測しています)。
変数の使い方
bash では変数に値を代入して再利用できます。代入時は = の前後にスペースを入れず、参照時は $ を頭に付けます。次の variables.sh を引数 arg1 arg2 付きで実行しました。
NAME=”Ubuntu”
VERSION=24
MSG=”Linux を学ぼう”
echo “OS: $NAME $VERSION”
echo “メッセージ: $MSG”
echo “引数の数: $#”
echo “スクリプト名: $0”
ubuntu:24.04 コンテナで実際に実行した結果です。
OS: Ubuntu 24
メッセージ: Linux を学ぼう
引数の数: 2
スクリプト名: /tmp/variables.sh
$# が 2、$0 が /tmp/variables.sh と表示され、引数の数とスクリプト名がきちんと取れています。よく使う特殊変数をまとめました。
| 変数 | 意味 | 例 |
|---|---|---|
$1 〜 $9 |
スクリプトに渡した引数 | bash script.sh hello → $1 が hello |
$# |
引数の個数 | bash script.sh a b c → 3 |
$0 |
スクリプト名(パス) | 実測では /tmp/variables.sh |
$@ |
全引数(各引数を個別に扱う) | ループで 1 個ずつ処理するときに使う |
$$ |
現在のシェルのプロセスID | 一時ファイル名に使うと衝突しにくい |
注意:= の前後にスペースを入れない
変数への代入は NAME="Ubuntu" のように = の前後にスペースを入れないでください。NAME = "Ubuntu" と書くと bash は NAME をコマンドだと解釈し、実測では bash: NAME: command not found(終了コード 127)になりました。初心者が最もハマるポイントです。
条件分岐(if文)の書き方
bashの条件分岐は if [ 条件 ]; then 〜 fi の形で書きます。[ の後ろと ] の前には必ずスペースが必要です。次の condition.sh を実行しました。
FILE=”/tmp/testfile.txt”
touch “$FILE”
if [ -f “$FILE” ]; then
echo “ファイルが存在します: $FILE”
else
echo “ファイルが存在しません”
fi
NUM=10
if [ “$NUM” -gt 5 ]; then
echo “$NUM は 5 より大きい”
fi
Ubuntu 24.04(bash 5.2.21)での実行結果です。
ファイルが存在します: /tmp/testfile.txt
10 は 5 より大きい
よく使う条件式をまとめました。
| 条件式 | 意味 |
|---|---|
-f ファイル |
ファイルが存在する |
-d ディレクトリ |
ディレクトリが存在する |
-z "$変数" |
変数が空文字 |
-n "$変数" |
変数が空文字でない |
"$a" = "$b" |
文字列が等しい |
"$a" != "$b" |
文字列が等しくない |
"$a" -eq "$b" |
数値が等しい |
"$a" -gt "$b" |
$a が $b より大きい |
"$a" -lt "$b" |
$a が $b より小さい |
ループ(for・while)の書き方
bash には for ループと while ループがあります。どちらも実際に動かして確認しました。
①forループ
for i in 1 2 3 4 5; do
echo ” ループ回数: $i”
done
②whileループ
while [ “$COUNT” -le 3 ]; do
echo ” カウント: $COUNT”
COUNT=$((COUNT + 1))
done
ubuntu:24.04 コンテナでの実行結果(変数・条件分岐・ループをまとめて実測)です。

=== for ループ ===
ループ回数: 1
ループ回数: 2
ループ回数: 3
ループ回数: 4
ループ回数: 5
=== while ループ ===
カウント: 1
カウント: 2
カウント: 3
算術演算は $((式)) で行います。COUNT=$((COUNT + 1)) は C 言語の COUNT++ に相当し、while ループのカウンタを1ずつ増やしています。
関数の定義と呼び出し
繰り返し使う処理は関数にまとめると、スクリプトがすっきりします。bash の関数は 関数名() { 〜 } で定義します。
greet() {
local name=”$1″
echo “こんにちは、$name さん!”
}
add() {
local a=”$1″
local b=”$2″
echo $((a + b))
}
greet “Ubuntu”
greet “World”
result=$(add 10 20)
echo “10 + 20 = $result”
ubuntu:24.04 コンテナでの実行結果(実測)です。終了コードの確認も同じスクリプトの後で行いました。

こんにちは、Ubuntu さん!
こんにちは、World さん!
10 + 20 = 30
ポイントは 2 つです。
localをつけることで、関数内だけで有効なローカル変数になります。付けないとスクリプト全体に影響が出ますresult=$(add 10 20)の$()はコマンド置換といい、関数の出力(echoした値)を変数に代入できます
終了コードとエラー処理
コマンドが成功したかどうかは「終了コード($?)」で確認できます。成功は 0、失敗は 1 以上の値が返ります。実測では、存在するファイルの ls は 0、存在しないファイルの ls は 2 を返しました。
/tmp/functions.sh
終了コード: 0
$ ls /nonexistent 2>/dev/null; echo “終了コード(失敗): $?”
終了コード(失敗): 2
エラー時に終了コードが 1 とは限らない点に注意してください(ls は引数エラーで 2 を返します)。大事なのは「0なら成功、0以外なら失敗」という判定です。スクリプトで安全に止めたい場合は set -e が便利です。
cp: cannot stat ‘/tmp/nope_source.txt’: No such file or directory
この行は set -e なしだと実行される
スクリプト全体の終了コード: 0
$ bash withset.sh # 先頭に set -e
cp: cannot stat ‘/tmp/nope_source.txt’: No such file or directory
スクリプト全体の終了コード: 1
実測のとおり、set -e が無いと cp が失敗しても次の行が実行され、スクリプト全体は 0(成功)で終わってしまいます。set -e を先頭に書くと、失敗した時点で止まり全体の終了コードも 1 になります。バグの早期発見に役立つので、本番用スクリプトでは付けておくのがおすすめです。
shellcheckでスクリプトを検証する
書いたスクリプトに問題がないか確認するには shellcheck が便利です。Ubuntu 24.04 では apt で簡単にインストールできます。
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 shellcheck amd64 0.9.0-1 [2845 kB]
Setting up shellcheck (0.9.0-1) …
$ shellcheck –version
ShellCheck – shell script analysis tool
version: 0.9.0
Ubuntu 24.04 では shellcheck 0.9.0(パッケージ 0.9.0-1、ダウンロードサイズ約2,845kB)が入りました。使い方はスクリプトファイルを引数に渡すだけです。試しに、クォート漏れと ls のループを含む「バグありスクリプト」に掛けてみました。

In buggy.sh line 3:
echo Hello $name
^—^ SC2086 (info): Double quote to prevent globbing and word splitting.
In buggy.sh line 4:
for f in $(ls /tmp); do
^——–^ SC2045 (error): Iterating over ls output is fragile. Use globs.
In buggy.sh line 5:
echo $f
^– SC2086 (info): Double quote to prevent globbing and word splitting.
$ echo $?
1
実測では SC2086(変数のクォート漏れ:info)と SC2045(ls の結果でループするのは壊れやすい:error)を検出し、終了コードは 1 でした。指摘どおり echo "$name" のようにクォートを付け、for f in /tmp/* のように glob へ書き換えると、警告ゼロ・終了コード0になりました。
正直、最初は shellcheck の警告を無視しがちなのですが、指摘を直すと「変数展開の落とし穴」や「クォートの付け忘れ」が事前にわかります。本番環境で動かす前に必ずかける習慣をつけましょう。
よくあるエラーと解決策
初心者がつまずくエラーを、実際にコンテナで再現しました。再現した本物のメッセージで対処法をまとめます。
| エラーメッセージ(実測) | 原因 | 解決策 |
|---|---|---|
Permission denied |
実行権限がない状態で ./script.sh を実行 |
chmod +x スクリプト名.sh を実行 |
NAME: command not found(終了コード127) |
NAME = "値" のように = の前後にスペースを入れた |
NAME="値" とスペースなしで書く |
cannot execute: required file not found(終了コード127) |
Windows で保存したファイルの改行コードが CRLF |
sed -i 's/\r//' スクリプト名.sh で CR を除去 |
syntax error near unexpected token |
構文ミス(fi 忘れ、; 漏れなど) |
shellcheck スクリプト名.sh でエラー箇所を特定 |
Windows で編集したファイルの改行コードに注意(実測で分かった意外な挙動)
Windows のメモ帳などで保存したファイルは改行コードが CRLF(\r\n) になることがあります。古い解説では /bin/bash^M: bad interpreter と出ると書かれていますが、Ubuntu 24.04 の bash 5.2.21 で実際に CRLF スクリプトを実行したところ、メッセージは cannot execute: required file not found(終了コード127)でした。エラー文言は環境で変わります。判定は file スクリプト名.sh が確実です。
crlf.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
$ ./crlf.sh
bash: ./crlf.sh: cannot execute: required file not found
$ sed -i ‘s/\r//’ crlf.sh && file crlf.sh
crlf.sh: Bourne-Again shell script, ASCII text executable
$ ./crlf.sh
test
Ubuntu バージョンによる違い
Ubuntu 22.04 と 24.04 で bash のバージョンは異なりますが、本記事で紹介した基本構文はどちらでも同様に動作します。実際に両方のコンテナで bash --version を実測しました。

| Ubuntu バージョン | bash バージョン(実測) | パッケージ | サポート期間 |
|---|---|---|---|
| Ubuntu 22.04.5 LTS | 5.1.16(1)-release | 5.1-6ubuntu1.1 |
2027年4月まで標準サポート |
| Ubuntu 24.04.4 LTS | 5.2.21(1)-release | 5.2.21-2ubuntu4 |
2029年4月まで標準サポート(推奨) |
どちらのバージョンでも本記事の内容は動作しますが、新しいサーバーを立てるなら Ubuntu 24.04 LTS を選ぶとサポート期間が長くて安心です。
まとめ
本記事では Ubuntu 24.04 LTS の bash 5.2.21 を docker run --rm ubuntu:24.04 で実際に動かし、bashスクリプトの基本を実測結果とともに解説しました。
#!/bin/bashのシバン行を先頭に書き、chmod +xで実行権限を付与する- 変数は
NAME="値"で代入し、$NAMEで参照する(= の前後にスペースなし。間違えると終了コード127) - 条件分岐は
if [ 条件 ]; then 〜 fi、[の前後のスペースに注意 for i in ...; do 〜 doneとwhile [ 条件 ]; do 〜 doneでループ処理- 関数は
関数名() { 〜 }で定義し、localでローカル変数を使う - 終了コード
$?(0=成功、0以外=失敗)でエラーチェック。set -eで失敗時に即停止 shellcheck 0.9.0はSC2086/SC2045などを実際に検出。本番前に必ずかける
本格的にサーバーを運用するなら、VPS でスクリプトを動かすのがおすすめです。VPS比較おすすめ7選【実測ベンチ】 を参考に、自分に合ったプランを選んでみてください。



コメント