関数
| 対応: | name() { } (POSIX構文) | POSIX(sh互換) |
|---|---|---|
| function name { } (bash拡張構文) | Bash(bash拡張) |
『シェルスクリプト』の関数は、処理をまとめて名前を付けて再利用できる仕組みです。定義構文には function name { } と name() { } の2種類があり、どちらも同じように動作します。引数は呼び出し時に空白区切りで渡し、関数内では $1 $2 … の位置パラメータで受け取ります。値を「返す」方法は2通りあり、return は終了ステータス(0〜255 の整数)を返すだけで、文字列や数値を呼び出し元に渡したい場合は echo とコマンド置換($())を組み合わせます。変数のスコープは local キーワードで制御でき、関数内だけで有効なローカル変数を宣言できます。
定義構文
関数は2つの構文で定義できます。function キーワードを付ける書き方と、付けない POSIX 準拠の書き方があります。どちらも { } ブロック内に処理を記述し、呼び出し前に定義されている必要があります。
| 構文 | 説明 |
|---|---|
function name { } | bash 拡張の書き方です。function キーワードを付ける場合は () を省略できます。 |
name() { } | POSIX 準拠の書き方です。sh でも動作します。bash スクリプトではこちらが広く使われます。 |
function name() { } | function キーワードと () を両方書いた書き方です。bash のみで有効です。 |
# -----------------------------------------------
# 2 つの定義構文(動作は同じです)
# -----------------------------------------------
# 書き方 1: function キーワードあり(() 省略可)
function greet {
echo "こんにちは!"
}
# 書き方 2: POSIX 準拠(sh でも動作します)
greet() {
echo "こんにちは!"
}
# 呼び出し方(コマンドと同じ書き方です)
greet
引数($1 $2 $@ $#)
関数に引数を渡すには呼び出し時に空白区切りで値を並べます。関数内では $1 $2 … で位置パラメータとして受け取ります。スクリプト全体の引数と同じ変数名ですが、関数内では関数に渡した引数に上書きされます。
| 変数 | 意味 | 説明 |
|---|---|---|
$1 $2 … | 位置パラメータ | 1 番目・2 番目 … の引数を受け取ります。 |
$@ | 全引数(各要素) | 全引数を個別要素として展開します。"$@" とダブルクォートで囲むとスペースを含む引数も正しく扱えます。 |
$* | 全引数(1 文字列) | 全引数を IFS 区切りの 1 文字列として展開します。通常は $@ を使います。 |
$# | 引数の個数 | 渡された引数の数を返します。引数チェックに使います。 |
# -----------------------------------------------
# 引数の受け取り方
# -----------------------------------------------
# 引数を 2 つ受け取る関数の例
show_info() {
# $1 に 1 番目の引数、$2 に 2 番目の引数が入ります
local name="$1"
local grade="$2"
echo "名前: ${name} 等級: ${grade}"
}
# 引数の個数チェック
check_args() {
# $# で引数の数を確認します
if [ "$#" -lt 2 ]; then
echo "エラー: 引数が足りません(必要: 2 個、渡された: $# 個)"
return 1
fi
echo "受け取った引数: $@"
}
return と echo の違い(値の返し方)
return は関数の終了ステータス(0〜255 の整数)を設定するだけです。文字列や計算結果を呼び出し元に渡したい場合は echo で出力し、$() コマンド置換で受け取ります。
| 方法 | 戻せる値 | 受け取り方 | 説明 |
|---|---|---|---|
return N | 0〜255 の整数のみ | $? | 成功・失敗などの終了ステータスを返します。0 が成功、1 以上がエラーの慣習です。 |
echo 値 | 文字列・数値・複数行 | $(関数名) | 標準出力に出力して呼び出し元でコマンド置換により受け取ります。 |
# -----------------------------------------------
# return: 終了ステータスを返します(0〜255 の整数のみ)
# -----------------------------------------------
is_valid_grade() {
local grade="$1"
# 等級が 1〜5 の範囲内かどうかを確認します
if [ "${grade}" -ge 1 ] && [ "${grade}" -le 5 ]; then
return 0 # 正常(成功)
else
return 1 # 異常(失敗)
fi
}
# $? で終了ステータスを受け取ります
is_valid_grade 3
echo "終了ステータス: $?" # 0
is_valid_grade 9
echo "終了ステータス: $?" # 1
# -----------------------------------------------
# echo: 文字列・数値を呼び出し元に渡します
# -----------------------------------------------
get_greeting() {
local name="$1"
# 文字列を返したいときは echo で出力します
echo "おはようございます、${name}さん"
}
# $() コマンド置換で関数の出力を受け取ります
message=$(get_greeting "五条悟")
echo "${message}"
local によるスコープ制御
シェルスクリプトの変数はデフォルトでグローバルスコープです。関数内で local を使うと、その変数はその関数内だけで有効になります。local を使わないと、関数内での変数変更がスクリプト全体に影響します。
| スコープ | 宣言方法 | 説明 |
|---|---|---|
| グローバル | 通常の代入(var=値) | スクリプト全体から参照・変更できます。関数の外でも影響が及びます。 |
| ローカル | local var=値 | 宣言した関数の内部だけで有効です。関数が終了すると破棄されます。 |
| 環境変数 | export var=値 | 子プロセスに引き継がれます。関数内で export すると子プロセスからも参照できます。 |
# -----------------------------------------------
# local を使わない場合(グローバル変数が変わります)
# -----------------------------------------------
name="五条悟" # グローバル変数
change_name_bad() {
# local なしで代入すると、グローバルの name が変わります
name="伏黒恵"
echo "関数内: ${name}"
}
echo "呼び出し前: ${name}" # 五条悟
change_name_bad
echo "呼び出し後: ${name}" # 伏黒恵 ← グローバルが変わってしまいます
# -----------------------------------------------
# local を使う場合(グローバル変数を守ります)
# -----------------------------------------------
name="五条悟" # グローバル変数
change_name_good() {
# local をつけると関数内だけの変数になります
local name="伏黒恵"
echo "関数内: ${name}" # 伏黒恵
}
echo "呼び出し前: ${name}" # 五条悟
change_name_good
echo "呼び出し後: ${name}" # 五条悟 ← グローバルは変わりません
サンプルコード
jjk_function_basic.sh
#!/bin/bash
# -----------------------------------------------
# 呪術廻戦のキャラクターで
# 関数の定義・引数・return・echo の使い方を確認します
# -----------------------------------------------
# -----------------------------------------------
# 関数定義: キャラクター情報を表示します
# 引数: $1=名前 $2=等級 $3=術式
# -----------------------------------------------
show_jujutsushi() {
# 引数が 3 つ揃っているか確認します
if [ "$#" -ne 3 ]; then
echo "エラー: 引数を 3 つ指定してください"
return 1
fi
local name="$1"
local grade="$2"
local jutsu="$3"
echo "┌─────────────────────────────┐"
printf "│ 名前: %-20s │\n" "${name}"
printf "│ 等級: %-20s │\n" "${grade}"
printf "│ 術式: %-20s │\n" "${jutsu}"
echo "└─────────────────────────────┘"
return 0
}
# -----------------------------------------------
# 関数定義: 等級が特級かどうかを判定します
# 引数: $1=等級文字列
# return: 0=特級, 1=特級以外
# -----------------------------------------------
is_special_grade() {
local grade="$1"
if [ "${grade}" = "特級" ]; then
return 0 # 特級です(成功)
else
return 1 # 特級ではありません(失敗)
fi
}
# -----------------------------------------------
# 関数定義: キャラクターの肩書きを返します
# 引数: $1=名前
# echo: 肩書き文字列を出力します
# -----------------------------------------------
get_title() {
local name="$1"
case "${name}" in
"五条悟") echo "最強の呪術師" ;;
"両面宿儺") echo "呪いの王" ;;
"虎杖悠仁") echo "宿儺の器" ;;
"伏黒恵") echo "十種影法術の使い手" ;;
"釘崎野薔薇") echo "芻霊呪法の使い手" ;;
*) echo "呪術師" ;;
esac
}
# -----------------------------------------------
# メイン処理
# -----------------------------------------------
echo "=== 呪術廻戦 キャラクター図鑑 ==="
echo ""
# キャラクターデータを定義します
declare -a names=("五条悟" "両面宿儺" "虎杖悠仁" "伏黒恵" "釘崎野薔薇")
declare -a grades=("特級" "特級" "1級" "1級補佐" "3級")
declare -a jutsus=("無下限呪術" "解・捌" "発勁" "十種影法術" "芻霊呪法")
for ((i=0; i<${#names[@]}; i++)); do
# 関数を呼び出してキャラクター情報を表示します
show_jujutsushi "${names[$i]}" "${grades[$i]}" "${jutsus[$i]}"
# return の終了ステータスで特級かどうかを判定します
is_special_grade "${grades[$i]}"
if [ "$?" -eq 0 ]; then
echo " ★ 特級呪術師・呪霊に認定されています"
fi
# echo + $() で肩書きを受け取ります
title=$(get_title "${names[$i]}")
echo " 肩書き: ${title}"
echo ""
done
$ chmod +x jjk_function_basic.sh $ ./jjk_function_basic.sh === 呪術廻戦 キャラクター図鑑 === ┌─────────────────────────────┐ │ 名前: 五条悟 │ │ 等級: 特級 │ │ 術式: 無下限呪術 │ └─────────────────────────────┘ ★ 特級呪術師・呪霊に認定されています 肩書き: 最強の呪術師 ┌─────────────────────────────┐ │ 名前: 両面宿儺 │ │ 等級: 特級 │ │ 術式: 解・捌 │ └─────────────────────────────┘ ★ 特級呪術師・呪霊に認定されています 肩書き: 呪いの王 ┌─────────────────────────────┐ │ 名前: 虎杖悠仁 │ │ 等級: 1級 │ │ 術式: 発勁 │ └─────────────────────────────┘ 肩書き: 宿儺の器 ┌─────────────────────────────┐ │ 名前: 伏黒恵 │ │ 等級: 1級補佐 │ │ 術式: 十種影法術 │ └─────────────────────────────┘ 肩書き: 十種影法術の使い手 ┌─────────────────────────────┐ │ 名前: 釘崎野薔薇 │ │ 等級: 3級 │ │ 術式: 芻霊呪法 │ └─────────────────────────────┘ 肩書き: 芻霊呪法の使い手
jjk_function_scope.sh
#!/bin/bash
# -----------------------------------------------
# 呪術廻戦のキャラクターで
# local によるスコープ制御を確認します
# -----------------------------------------------
# グローバル変数: 現在の担当キャラクターを管理します
current_user="未設定"
mission_count=0
# -----------------------------------------------
# 関数定義: ミッションを実行します
# local を使ってグローバル変数を守ります
# -----------------------------------------------
execute_mission() {
local name="$1" # ローカル変数: 関数内のみ有効
local mission="$2" # ローカル変数: 関数内のみ有効
local result="" # ローカル変数: 後で代入します
# グローバル変数 mission_count を更新します
# (意図的にグローバルを変更する場合は local を付けません)
mission_count=$((mission_count + 1))
# 術式に応じて結果を設定します(local 変数に代入します)
case "${name}" in
"五条悟") result="無下限で完封。圧勝。" ;;
"虎杖悠仁") result="宿儺の力で突破。辛勝。" ;;
"伏黒恵") result="式神を駆使して攻略。" ;;
"釘崎野薔薇") result="芻霊呪法で撃破。" ;;
"両面宿儺") result="問答無用で消滅させた。" ;;
esac
echo " [ミッション ${mission_count}] ${name}: ${mission}"
echo " → ${result}"
}
# -----------------------------------------------
# 関数定義: ユーザーを切り替えます
# local なしの代入でグローバル変数を更新します
# -----------------------------------------------
switch_user() {
# local を付けないので current_user グローバルが変わります
current_user="$1"
echo "担当変更 → ${current_user}"
}
# -----------------------------------------------
# メイン処理
# -----------------------------------------------
echo "=== スコープ確認: ローカル変数はグローバルに影響しません ==="
echo ""
echo "開始時の current_user: ${current_user}"
echo "開始時の mission_count: ${mission_count}"
echo ""
switch_user "五条悟"
execute_mission "五条悟" "特級呪霊の討伐"
switch_user "虎杖悠仁"
execute_mission "虎杖悠仁" "宿儺の指の回収"
switch_user "伏黒恵"
execute_mission "伏黒恵" "封印された式神の解放"
switch_user "釘崎野薔薇"
execute_mission "釘崎野薔薇" "呪物の破壊"
switch_user "両面宿儺"
execute_mission "両面宿儺" "全てを破壊する"
echo ""
echo "=== グローバル変数の最終状態 ==="
echo "current_user: ${current_user} ← switch_user で変わりました"
echo "mission_count: ${mission_count} ← execute_mission で累積されました"
echo ""
echo "(local 変数の name / mission / result は関数終了後に消えています)"
$ chmod +x jjk_function_scope.sh
$ ./jjk_function_scope.sh
=== スコープ確認: ローカル変数はグローバルに影響しません ===
開始時の current_user: 未設定
開始時の mission_count: 0
担当変更 → 五条悟
[ミッション 1] 五条悟: 特級呪霊の討伐
→ 無下限で完封。圧勝。
担当変更 → 虎杖悠仁
[ミッション 2] 虎杖悠仁: 宿儺の指の回収
→ 宿儺の力で突破。辛勝。
担当変更 → 伏黒恵
[ミッション 3] 伏黒恵: 封印された式神の解放
→ 式神を駆使して攻略。
担当変更 → 釘崎野薔薇
[ミッション 4] 釘崎野薔薇: 呪物の破壊
→ 芻霊呪法で撃破。
担当変更 → 両面宿儺
[ミッション 5] 両面宿儺: 全てを破壊する
→ 問答無用で消滅させた。
=== グローバル変数の最終状態 ===
current_user: 両面宿儺 ← switch_user で変わりました
mission_count: 5 ← execute_mission で累積されました
(local 変数の name / mission / result は関数終了後に消えています)
概要
『シェルスクリプト』の関数定義には function name { } と name() { } の2種類があります。引数は呼び出し時に空白区切りで渡し、関数内で $1 $2 … $@ $# を使って受け取ります。値を返す方法は return(終了ステータス 0〜255)と echo(文字列・数値)の2通りで、文字列を返したい場合は echo で出力して呼び出し元で $(関数名) とコマンド置換で受け取ります。変数のスコープはデフォルトでグローバルのため、関数内の変数には local を付けてグローバルへの意図しない影響を防ぐことを推奨します。スクリプトの引数処理については 特殊変数 も合わせて参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。