順番に読み進めながら学べます

関数 — 同じ処理を 1 か所にまとめる

この記事は、基礎コマンドからシェルスクリプトまでLinuxの実践的なスキルを1からマスターする「Linux入門講座の一部」です。
name() { ... } で処理を定義し $1で引数を受け取り、localで関数内だけの変数を作り、returnと $? で成否を分岐させて同じ検証ロジックを使い回す書き方を、図解と端末で確認します。

処理に名前を付ける — 関数定義と引数

同じ処理を何度も書く代わりに、関数としてまとめて名前で呼び出せます。

name() { ... }で定義し、本体は{}の間に書きます。

定義した後にnameと書くと、その処理が実行されます。

長いスクリプトを意味のある単位に分けられ、修正も 1 か所で済みます

また関数に値を渡すには、呼び出すときにname foo barのように引数を続けます。

関数の中では$1が 1 番目、$2が 2 番目の引数を表します(スクリプト本体の位置パラメータと同じ書き方です)。

引数は二重引用符で"$1"と囲むと、空白を含む値でも 1 つの引数として扱えます

greet() {                        # 関数を定義
  echo "hello, $1"
}
greet alice                      # hello, alice
greet bob                        # hello, bob
呼び出しと引数の対応
greet alice bob$1 = alice$2 = bob本体で $1 $2 を使う1 番目2 番目関数 greet の中
greet alice bobの値が$1 $2に入り、関数の本体でそれらを使って処理します。
書き方意味
name() { … }関数を定義するgreet() { echo "hi $1"; }
name 引数関数を呼び出すgreet alice
$1関数内で 1 番目の引数を参照echo "name=$1"
$2関数内で 2 番目の引数を参照echo "port=$2"

入力検証を関数にまとめて再利用するユーティリティスクリプトを作成します。

vi validate.shvalidate.shを開き、iで挿入モードに入って、先頭に#!/bin/shを書いてください。

② 値を 1 つ受け取り、その値が空かどうかを判定して結果を表示する関数を定義してください。関数内では$1で引数を参照してください。

③ 定義した関数を、異なる値を渡して複数回呼び出してください。

Escを押し:wqで保存してから、実行権限を付けてからスクリプトを実行し、各呼び出しの結果を確認してください。

⑤ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。(正しく実行できれば解説が表示されます)

Linux console
0 / 3 実行済み
Loading Linux Terminal...

関数内だけの変数 — local

関数の中でlocal v=...と宣言すると、その変数は関数の中だけで有効になり、関数を抜けると消えます。

localを付けないと、同じ名前の変数を関数の外でも書き換えてしまい、思わぬ副作用が起きます

関数を部品として安全に再利用するために、内部で使う作業用変数はlocalにします。

msg="outer"
show() {
  local msg="inner"            # 関数内だけの変数
  echo "in func: $msg"
}
show                           # in func: inner
echo "outside: $msg"           # outside: outer(外は変わらない)
local の見える範囲
msg=outerecho "$msg"outer と表示local msg=innerecho "$msg"inner と表示スクリプト全体関数の中 (local)
通常の変数は全体から見え、localの変数は関数の中だけで有効です。同名でも外側の値は変わりません。
書き方意味
local v=…関数内だけで有効な変数を作るlocal step=1
v=…スクリプト全体で有効な変数status=ready

作業用変数を local にして外側に影響しないことを確認するスクリプトを作成します。

vi scope.shscope.shを開き、iで挿入モードに入って、先頭に#!/bin/shを書いてください。

② 外側で変数を 1 つ設定し、同じ名前の変数をlocalで宣言して別の値を入れる関数を定義してください。

③ 関数を呼び出した後に外側の変数を表示し、外側の値が変わっていないことを確認できる処理を書いてください。

Escを押し:wqで保存してから、実行権限を付けてからスクリプトを実行してください。

⑤ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。

Linux console
0 / 3 実行済み
Loading Linux Terminal...

成否を返す — return と $?

関数はreturn Nで終了コードを返せます。

0が成功、0以外が失敗という慣習で、呼び出した直後に$?でその値を確認できます。

if check "$x"; then ...のように、関数の成否でそのまま分岐すると、検証と処理の流れが読みやすくなります

is_num() {
  case "$1" in
    *[!0-9]*|"") return 1 ;;     # 数字以外を含むか空なら失敗
    *) return 0 ;;
  esac
}
is_num 12; echo "12 -> $?"       # 12 -> 0
is_num abc; echo "abc -> $?"     # abc -> 1
return から $? で分岐する流れ
is_num "$1"return 0return 1成功の処理失敗の処理数値数値でない$? = 0 → 成功$? = 1 → 失敗
returnの値が$?に入り、if0を成功、0以外を失敗として分岐します。
書き方意味
return 0成功として関数を抜けるis_num 12; # 成功
return 1失敗として関数を抜けるis_num abc; # 失敗
$?直前の関数の戻り値を確認is_num 12; echo $?
if name x; then …戻り値で直接分岐するif is_num "$v"; then …; fi

数値かどうかを判定する関数を作り、戻り値で分岐するスクリプトを作成します。

vi isnum.shisnum.shを開き、iで挿入モードに入って、先頭に#!/bin/shを書いてください。

② 受け取った値が数字だけかを判定し、数字ならreturn 0、そうでなければreturn 1を返す関数を定義してください。

③ その関数をifの条件に直接置いて、複数の入力に対し成功・失敗のメッセージを出す処理を書いてください。

Escを押し:wqで保存してから、実行権限を付けてからスクリプトを実行し、判定結果を確認してください。

⑤ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。

Linux console
0 / 3 実行済み
Loading Linux Terminal...
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1シェル関数の中で 1 番目の引数を参照する書き方はどれですか?

Q2localを付けて宣言した変数の有効範囲はどれですか?

Q3関数の直前の戻り値を確認するのはどれですか?