関数を定義する
関数を定義する とは
シェルスクリプトの基本、関数を定義する方法をターミナルで実際に試してみましょう。本レッスンでは、関数を定義する の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
なぜ重要か
スクリプトが 50 行を超えてくると、同じ処理が複数箇所に登場し始めます。ログを書き出す処理、エラー時の通知、ファイルの存在確認。これらをそのままコピペで増やすと、後から仕様変更があったときに修正漏れが発生し、保守不能なスクリプトに育ってしまいます。bash の 関数 (function) は、共通処理を 1 か所にまとめて再利用するための基本的な仕組みで、これを覚えると 100 行を超えるスクリプトの可読性が劇的に上がります。
関数の定義方法
bash の関数は次のいずれかの形で定義します。どちらでも動きますが、簡潔な前者がよく使われます。
ターミナル
greet() {
echo "Hello, $1"
}
function greet() {
echo "Hello, $1"
}呼び出し方は普通のコマンドと同じです。関数名のあとに引数を並べるだけです。
ターミナル
greet alice
greet bobプレーンテキスト
Hello, alice
Hello, bob関数の引数
関数内では $1, $2, $@, $# などが「関数の引数」を意味します。スクリプト本体の位置引数とは別物なので、混乱しないように注意してください。
ターミナル
add() {
local a=$1
local b=$2
echo $((a + b))
}
result=$(add 3 5)
echo "$result" # 8local とスコープ
関数の中で変数を定義するときは local を付けます。これを忘れると、関数で使った変数がスクリプト全体に漏れてしまい、思わぬ副作用の原因になります。
ターミナル
counter() {
local i=0
while [[ "$i" -lt 3 ]]; do
echo "$i"
i=$((i + 1))
done
}関数の戻り値
bash の関数は「数値の終了ステータス」を返します。Python のように任意の値を return できるわけではありません。文字列を返したいときは、関数の中で echo して、呼び出し側で $(...) で取り込むのが定石です。
ターミナル
upper() {
echo "$1" | tr a-z A-Z
}
result=$(upper hello)
echo "$result" # HELLO終了ステータスは return で返します。
ターミナル
is_root() {
if [[ "$(id -u)" -eq 0 ]]; then
return 0
else
return 1
fi
}
if is_root; then
echo "root user"
else
echo "normal user"
fi0 が成功、1 以上が失敗です。これは Unix の伝統的なルールに従っており、関数を if の条件にそのまま渡せるのが綺麗です。
呼び出しと戻り値の流れ
関数の出力は標準出力に流れ、$(...) で文字列として受け取れる、という流れを掴んでおくと bash の関数が一気に使いやすくなります。
ログ関数の例
ターミナル
log() {
local level=$1
shift
local message="$*"
printf '[%s] [%s] %s\n' "$(date +%H:%M:%S)" "$level" "$message"
}
log INFO "start backup"
log ERROR "disk almost full"shift で $1 を取り除くと、残りの引数を $* でまとめて受け取れます。これでメッセージにスペースが入っていても自然に扱えます。
関数の整理パターン
大きめのスクリプトでは、最初に関数を全て定義し、最後で main 関数を呼ぶスタイルが扱いやすいです。
ターミナル
#!/bin/bash
set -euo pipefail
usage() {
echo "usage: $0 <env>"
}
deploy() {
echo "deploy to $1"
}
main() {
if [[ $# -lt 1 ]]; then
usage
exit 1
fi
deploy "$1"
}
main "$@"main "$@" でスクリプト引数を全て main 関数に渡し、本体の処理はその中で進めます。Python の if __name__ == "__main__": に近い思想です。
小さなスクリプトでも
main関数にまとめておくと、後でsourceで読み込んだときに勝手に実行されない、関数だけ使い回したい場合に便利、というメリットがあります。実務で 100 行を超えそうなスクリプトは最初から main スタイルで書く癖を付けると保守しやすくなります。
関数の再利用
別ファイルにまとめた関数群は、source (または .) で読み込めます。
ターミナル
# lib.sh
log() {
echo "[LOG] $*"
}ターミナル
# main.sh
source ./lib.sh
log "start"ライブラリ感覚で関数を共有でき、複数スクリプトでロジックを揃えやすくなります。
sourceはカレントシェルで実行されるため、関数だけでなくその場で変数も読み込まれます。逆にbash lib.shだと別プロセスになり、関数は呼び出し元に残らないので注意してください。
まとめ
name() { ... }で関数を定義し、コマンドのように呼び出す- 関数内の引数は
$1,$2,$@,$# - スコープは
localで閉じるのが安全 - 文字列の戻り値は echo +
$(...)で受け取る - 終了ステータスは
return 0/1で返し、ifの条件にも使える - 大きなスクリプトは
main "$@"パターンで構造化する - 共通関数は別ファイルにまとめて
sourceで読み込む
次のレッスン
次は 実践スクリプト作成 で、シェルスクリプトの基本、関数を定義する方法をターミナルで実際に試してみましょう を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 関数の定義 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 関数の定義 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
課題
- greet 関数を定義する
- greet "Linux" を呼び出して Hello, Linux を出力