Shell 関数の基本

ShellBeginner

はじめに

スクリプトを書くとき、同じコードブロックを何度も繰り返し記述する必要が出てくることがあります。そのような場合、コードを書き直したりコピー&ペーストしたりする代わりに、関数を使えます。

関数とは、特定の処理を実行する名前付きのコードブロックです。一度定義すれば、必要なときに何度でも呼び出せます。これにより、スクリプトを次のようにできます。

  • モジュール化: 読みやすく、管理しやすくなります。
  • 再利用可能: 一度書いたコードを何度も使えます。
  • 保守しやすい: ロジックを変更するとき、1 か所だけを更新すれば済みます。

すべての処理を上から下へ続く 1 つの長いコードブロックに書くと、スクリプトが大きくなったときに内容を把握しにくくなります。スクリプトを関数に分割することは、「その場しのぎの Shell ハック」から「保守しやすい自動化」へ進むための最初のステップの 1 つです。

この実験では、関数を使ってスクリプトを書き直す基本を学びます。次の操作を行います。

  1. 基本的なスクリプトを作成します。
  2. greet_user という名前の関数を定義します。
  3. 関数を呼び出して実行します。
  4. 関数がパラメーター(引数)を受け取れるように拡張します。

スクリプトファイルを作成する

まず、作業環境を準備します。コードを保存する functions.sh というファイルを作成します。

この段階では、スクリプトファイルは単なる入れ物です。この実験で重要なのはファイル自体ではなく、スクリプトを上から下へ続く 1 つの長い処理として書くのではなく、名前付きの部分に整理できるという考え方です。

まず、プロジェクトディレクトリへ移動してファイルを作成します。

cd ~/project
touch functions.sh

次に、テキストエディターでファイルを開き、標準的な Shebang ヘッダーを追加します。

nano functions.sh

ファイルの先頭に次の行を追加します。

#!/bin/bash

ファイルを保存し(Ctrl+O、Enter)、終了します(Ctrl+X)。

最後に、後で実行できるようにスクリプトへ実行権限を付与します。

chmod +x functions.sh

これで、コードを書き始める準備ができました。

関数を定義する

ここでは、greet_user という名前の関数を定義します。

Bash では、関数名の後ろに括弧 () を付け、コードブロックを波括弧 {} で囲んで関数を定義します。

関数を使うと、コマンドのまとまりに再利用可能な名前を付けられます。Shell スクリプトが読みやすくなるのはこのためです。あちこちに書かれたコマンドを直接読むのではなく、backup_files、check_disk、greet_user のような意味のある名前で処理内容を把握できるようになります。

構文は次のとおりです。

function_name() {
  ## Commands to execute
}

スクリプトをもう一度開きます。

nano functions.sh

Shebang 行の下に、次の関数定義を追加します。

#!/bin/bash

greet_user() {
  echo "Hello"
}

重要: この時点では、関数を定義しただけです。関数を実際に実行するようスクリプトへ指示していません。今スクリプトを実行しても、何も起こりません。これは初心者が混乱しやすい点です。関数を定義しても、自動的に実行されるわけではありません。

この違いが重要なのは、Shell スクリプトが上から順番に読み込まれて実行されるためです。関数定義によって Bash は関数の内容を認識しますが、関数本体は後で関数名を呼び出すまで実行されません。

ここではファイルを保存して終了してください。

関数を呼び出す

関数内のコードを実行するには、関数を「呼び出す」必要があります。Bash では、新しい行に関数名を書くだけで関数を呼び出せます。呼び出し時に括弧を付ける必要はありません。

多くのプログラミング言語では関数呼び出しに括弧を使うため、初心者にはこの書き方が特殊に見えることがあります。Bash では、greet_user だけを書くとコマンドとして扱われます。その名前の関数が存在すれば、Bash は関数本体を実行します。

スクリプトを開きます。

nano functions.sh

ファイルの末尾に関数呼び出しを追加します。

#!/bin/bash

greet_user() {
  echo "Hello"
}

## The Main Logic starts here
greet_user

ファイルを保存して終了します。

次に、スクリプトを実行します。

./functions.sh

スクリプトを実行すると、Shell は greet_user というコマンドを見つけ、関数定義を参照して echo "Hello" を実行し、その後の処理へ進みます。

この意味で、関数は現在のスクリプトまたは Shell セッション内だけに存在するカスタムコマンドのように動作します。そのため、関数は小さな Shell コマンドを組み合わせて、より高レベルの処理を作る際に役立ちます。

次の出力が表示されます。

Hello

関数に引数を渡す

「Hello」と表示するだけのように、常に同じ処理を行う関数には限界があります。関数をより便利にするには、関数へデータを渡します。このデータを引数と呼びます。

関数内では、スクリプトの引数と同じように、$1、$2 などの特殊な変数を使って引数にアクセスできます。

  • $1 は関数に渡された最初の引数を表します。
  • $2 は 2 番目の引数を表します。

これらは、関数が実行される時点でのスクリプト自身の位置パラメーターとは別のものです。つまり、関数は独自の小さな入力インターフェースを持てるため、異なる値で再利用しやすくなります。

ここでは、特定の名前を使って挨拶するように関数を変更します。

ステップ 1: 関数定義を更新する

ファイルを開きます。

nano functions.sh

greet_user 関数を変更し、固定文字列の代わりに $1 を使います。

greet_user() {
  echo "Hello $1"
}

ステップ 2: 関数呼び出しを更新する

関数が引数を受け取るようになったため、関数を呼び出すときに引数を渡す必要があります。

呼び出しを greet_user から greet_user "LabEx" に変更します。

ファイル全体は次のようになります。

#!/bin/bash

greet_user() {
  echo "Hello $1"
}

greet_user "LabEx"

ファイルを保存して終了します。

ステップ 3: スクリプトをテストする

もう一度スクリプトを実行します。

./functions.sh

出力は次のようになります。

Hello LabEx

これで、入力を受け取って処理するカスタムコマンドを作成できました。スクリプトの後の部分で greet_user "Alice" や greet_user "Bob" を呼び出すと、渡した名前に応じて動作します。

まとめ

この実験では、Bash 関数の基本を学びました。

  1. 定義: name() { ... } を使って、名前付きのコードブロックを作成する。
  2. 呼び出し: 関数名をそのまま入力して、関数を実行する。
  3. 引数: 関数にデータを渡し、$1、$2 などを使ってそのデータへアクセスする。

関数は複雑なスクリプトを構成する基本要素です。ロジックを整理し、処理の重複を減らし、コードを読みやすく保守しやすくできます。