シェルスクリプト

関数と引数

処理を関数へ分け、引数を受け取る再利用可能なスクリプトへ進みます。

シェルスクリプト入門の講座一覧

01

関数へ処理をまとめる

関数は、名前を付けた処理のまとまりです。呼び出し側から処理の目的が分かる名前を付けると、スクリプト全体を読みやすくできます。

メッセージ関数BASH
print_line() {
    printf '%s\n' '----------------'
}

print_line
printf 'レポート\n'
print_line
実行結果OUTPUT
----------------
レポート
----------------

関数を定義しただけでは実行されません。定義のあとで関数名を書いて呼び出します。

02

位置パラメーターで引数を受け取る

関数内の$1、$2は関数へ渡した引数です。スクリプト全体では、コマンドライン引数を表します。

show.shBASH
show_file() {
    local path="$1"
    printf '対象: %s\n' "$path"
}

if [[ $# -ne 1 ]]; then
    printf '使い方: %s ファイル\n' "$0" >&2
    exit 2
fi
show_file "$1"
実行例COMMAND
bash show.sh data/app.log
実行結果OUTPUT
対象: data/app.log

$#は引数の個数、$0はスクリプト名です。引数の個数を確認せずに$1を使うと、入力漏れで分かりにくいエラーになることがあります。

03

終了ステータスを返す

関数は値を返すというより、成功・失敗を終了ステータスで返す設計がよく使われます。成功を0、失敗を1以上にします。

読み取り可能か返すBASH
is_readable() {
    [[ -r "$1" ]]
}

if is_readable 'data/app.log'; then
    printf '読み取り可能です。\n'
else
    printf '読み取れません。\n' >&2
fi
実行結果OUTPUT
読み取り可能です。

関数の最後に実行した[[ ... ]]の結果がそのまま戻り値になります。文字列を返したい場合は、表示と終了ステータスを分ける設計を検討します。

04

localで変数の範囲を限定する

Bashの関数内でlocalを付けた変数は、その関数の中だけで使います。外側の変数を誤って上書きしないために、関数内の一時変数へ付けます。

localを使うBASH
make_message() {
    local subject="$1"
    printf '件名: %s\n' "$subject"
}

subject='外側の値'
make_message 'レポート'
printf '外側: %s\n' "$subject"
実行結果OUTPUT
件名: レポート
外側: 外側の値
05

getoptsでオプションを受け取る

実用的なスクリプトでは、-fや-nのようなオプションを受け取ることがあります。Bashのgetoptsを使うと、形式をそろえて処理できます。

greet.shBASH
name='world'
while getopts 'n:' option; do
    case "$option" in
        n) name="$OPTARG" ;;
        *) printf '使い方: %s [-n 名前]\n' "$0" >&2; exit 2 ;;
    esac
done
printf 'こんにちは、%sさん。\n' "$name"
実行例COMMAND / OUTPUT
bash greet.sh -n Mity
こんにちは、Mityさん。

n:のコロンは、-nに値が必要という意味です。複雑な引数仕様にする前に、使い方とエラー時の終了コードを決めておきます。

06

練習:ファイルの行数を調べる関数

ファイルパスを引数に受け取り、存在しなければエラー、存在すれば行数を表示するスクリプトを作ってください。

count.shBASH
count_lines() {
    local file="$1"
    if [[ ! -f "$file" ]]; then
        printf 'ファイルがありません: %s\n' "$file" >&2
        return 1
    fi
    wc -l < "$file"
}

if [[ $# -ne 1 ]]; then
    printf '使い方: %s ファイル\n' "$0" >&2
    exit 2
fi
printf '行数: %s\n' "$(count_lines "$1")"
実行例COMMAND / OUTPUT
bash count.sh data/app.log
行数: 3

次は安全なスクリプトと定期実行へ進み、失敗時の扱いやログを考えます。