【Linux】実用的なシェルスクリプトの書き方|配列・引数などを解説

Linux

前回、以下の記事でシェルスクリプトの書き方と実行方法について解説しました。
【Linux初心者向け】シェルスクリプトの書き方と実行方法|作業効率アップ

複数のコマンドをただ実行するだけであれば、前回の記事で紹介した内容だけで十分と思います。

しかし、より実用的なシェルスクリプトを作成したい場合、
引数や関数など活用できる機能がほかにも多々あります。

かけりゅー
かけりゅー

本記事では、筆者の経験をもとに
柔軟でメンテナンスしやすいシェルスクリプトの作成に便利な機能を紹介します。

配列

配列とは、複数の値を一つの変数として管理する仕組みです。

配列の宣言・初期化

配列を使う際は、はじめに以下のように値を設定します。

fruits=("apple" "orange" "grape")

また、あとから要素を追加したい場合、次のように記述します。

fruits+=("lemon")

このように設定することで、
インデックスを意識せず、配列の管理が容易になります。

一方、インデックスを自分で指定したい場合、
インデックスを自分で管理する必要がありますが、次のように設定することもできます。

fruits[0]="apple"
fruits[1]="orange"
fruits[2]="grape"
fruits[3]="lemon"

要素へのアクセス

特定の要素へアクセスする場合、次のように記述します。

echo "${fruits[0]}"

また、ループで全要素にアクセスしたい場合は、次のように記述します。

for fruit in "${fruits[@]}"; do
    echo "$fruit"
done
かけりゅー
かけりゅー

例えば、複数のログを収集するスクリプトを作成したいときに、
配列に収集するログファイルの名前を設定することで、管理しやすくなります。

引数

引数とは、シェルスクリプトを実行するときに外部(呼び出し元)から渡される値のことです。

シェルスクリプトの実行時、以下のように起動することで引数を渡します。

$ ./test.sh 引数1 引数2

渡された引数は、次のように$1$2 と記述することで参照できます。

echo "第1引数:$1"
echo "第2引数:$2"

同じシェルスクリプトであっても、引数に渡す値によって処理を変えることができるため、
汎用性のあるシェルスクリプトが作成できるようになります。

例えば、ログ収集スクリプトの場合、
収集したログを保存するアーカイブファイル名を引数で指定できるようにすることで、
何の目的で収集したログかを管理しやすくなります。

引数チェック

引数を使用するシェルスクリプトでは、
引数が指定されないまま実行されると、意図しない動作となる可能性があります。

そういった意図しない動作を防ぐため、
必要に応じて引数が正しく設定されているかチェックする必要があります。

if [ $# -ne 1 ]; then
    echo "使い方:./test.sh ディレクトリ名"
    exit 1
fi

if文の条件で指定している$#は、設定された引数の個数を表します。

上記は、あくまでも引数チェックの一例ですが、
シェルスクリプト実行時の引数が1つでない場合にメッセージを表示して終了します。

このように、意図した引数が設定されていない場合に、
意図しない処理が実行される前にスクリプトを終了するためにチェックを行います。

終了ステータスとエラー処理

終了ステータスとは、Linuxコマンドの実行結果を示す値です。
コマンドの正常終了時は0、エラー終了時は0以外の値を返します。

cp test.txt backup/
echo $?

終了ステータスは、$?で取得できます。
上記の場合、コピーに成功した場合は0、コピーに失敗した場合は0以外の値を取得します。

なお、$? で取得できるのは直前に実行したコマンドの終了ステータスです。
別のコマンドを実行すると終了ステータスの値は上書きされるため、
終了ステータスは対象コマンドの実行直後に参照してください。

終了ステータスを利用することで、
コマンドの成功時は処理継続、失敗時はスクリプトを終了のように処理を分岐することができます。

また、シェルスクリプト自身も次のように、
exitで指定した終了ステータスを返すことができます。

# 正常終了
exit 0

# 異常終了
exit 1

自身が他のシェルスクリプトから実行されていた場合に、
呼び出し元に終了ステータスを返すことができます。

かけりゅー
かけりゅー

例えば、シェルスクリプトの処理でディレクトリの作成に失敗した場合に、
その後の処理が意図しないパスで実行されないよう防ぐ目的で使います。

関数

関数とは、複数の処理を一つの固まりとしてまとめたものです。
関数を呼び出すことで、関数内にまとめた処理を実行します。

run_cmd()
{
    echo "# $*"
    "$@"
    echo
}

例えば、上記はコマンドを表示してから実行するための関数です。

$*は、関数に渡されたすべての引数を1つの文字列として扱います。
$@は、関数に渡されたすべての引数をそのまま文字列として展開します。

run_cmd mkdir /home/user/work

このように記述した場合、「# mkdir /home/user/work」と表示したあと、
“$@”で mkdir /home/user/work が展開され、ディレクトリ作成を実行します。

同じ流れの処理を複数回に渡って使用する場合に、
関数を利用して整理することで保守性の向上に繋がります。

設定ファイル読み込み

シェルスクリプトでは、シェル変数に値を設定して使用できます。
このとき、必要に応じてシェル変数を別ファイルに分けて管理することもできます。

例えば、設定ファイルとしてenv.confを作成し、以下を記述します。

TEST_PATH=/home/dbg/test

作成したenv.confに記述した値をシェルスクリプトで使用したい場合、
次のように、シェルスクリプトでsourceコマンドを利用して読み込みます。

#!/bin/bash

# 設定ファイルenv.confの読み込み
source env.conf

例えば、試験環境ごとにディレクトリの構成に差があるとき、
設定ファイルの内容を環境に合わせることで、
シェルスクリプトをその環境でも使うことができるようになります。

読み込んだ設定値は、通常のシェル変数と同じように${TEST_PATH}として使用できます。

設定値とスクリプトの処理を分離できるため、
使用する際に必要な設定がわかりやすくなるほか、保守性の向上にも繋がります。

まとめ

本記事では、実用的なシェルスクリプトを作る上でよく利用する機能について紹介しました。

単純にコマンドを実行するだけであれば、以下の記事で紹介した内容で足りることが多いです。
【Linux初心者向け】シェルスクリプトの書き方と実行方法|作業効率アップ

しかし、実務で長く使用することを踏まえると、
汎用性保守性といった部分も気にしなければなりません。

実際、筆者も試験環境を更新したときなどに、
既存のシェルスクリプトをメンテナンスするケースがありました。
保守性に欠けていると、そういったとき途端にシェルスクリプトがゴミと化す可能性もゼロではありません。

本記事で紹介した機能を上手く使うことで、
実務でも利用しやすい実用的なシェルスクリプトを作成できるようになります。

かけりゅー
かけりゅー

慣れないと取り入れづらい機能かもしれないですが、
少しずつ試してみて、活用できるよう目指してみるのがよいと思います。

コメント