Bash 入門

Bash 変数(バリアブル)進階

本章では、Bashスクリプト内でバリアブル(変数)に値を代入する方法、およびそれらの値にアクセスする方法について深く掘り下げます。

構文、ベストプラクティス、そしてよくある落とし穴について網羅し、スクリプト作成時にバリアブルを効率的に使用できるようサポートします。バリアブルを理解することは、さまざまな状況に適応し、情報を効果的に処理するオートメーション(自動化)スクリプトを作成する上で不可欠です。

1. 変数への代入

Bashにおけるバリアブルへの代入は非常にシンプルかつ直接的です。基本構文は以下の通りです:

variable_name=value

極めて重要な注意事項:

  • イコールの両側にスペースを入れない: イコール (=) のどちら側にもスペースを置いてはいけません。スペースを入れると、Bashは各パーツを独立したコマンドや引数(パラメータ)として誤って解釈し、構文エラーを引き起こします。
  • ケースセンシティブ(大文字・小文字の区別): 変数名はケースセンシティブです。myVariablemyvariable は全く別のバリアブルとして扱われます。
  • 記述的な名前を使用する: これは優れたプログラミング習慣です。変数の用途を示す名前を使用しましょう。例えば、u よりも username の方がはるかに理解しやすくなります。
  • 命名規則(コンベンション): ユーザー定義の変数名に大文字を使用することも可能ですが、慣習として、独自のローカル変数には小文字を使用し、システムレベルの環境変数(これについては次章で詳述します)にはすべて大文字を使用するのが一般的です。

基本例:

name="John Doe"
age=30
city="New York"

1.1 コマンドの出力を変数に代入する (コマンド置換)

システムコマンドの実行結果をバリアブルに格納したい場面は多々あります。これは「コマンド置換(Command Substitution)」によって実現できます。主に2つの方法があります:

方法 1:バッククォート (`) を使用する

current_date=`date`

方法 2:$() を使用する (強く推奨)

current_date=$(date)

$() 構文は、可読性が高く、多層のネスト(入れ子)をサポートし、複雑なエスケープ文字を処理する際のトラブルを回避できるため、強く推奨されます。

実戦例:

# 現在のワーキングディレクトリを取得して変数に格納
current_directory=$(pwd)
echo "現在のディレクトリは: $current_directory"

# 現在のディレクトリ内のファイル/行数を取得
file_count=$(ls -l | wc -l)
echo "このディレクトリ内のアイテム数は: $file_count"

1.2 スペースを含む値の処理(シングルクォート vs ダブルクォート)

代入する値にスペースが含まれる場合、クォート(単一引用符または二重引用符)で囲む必要があります。そうしないと、Bashはスペース以降の内容を別のコマンドとして認識してしまいます。

  • ダブルクォート ("..."): 文字列内部でのバリアブル展開やコマンド置換(つまり $ 記号の解析)を許可します。
  • シングルクォート ('...'): 文字列を純粋なリテラル(見たままの文字列)として扱い、バリアブル展開やコマンド置換を一切阻止します。

比較例:

name="Alice"

# ダブルクォートを使用:変数が解析される
greeting="Hello, $name!"

# シングルクォートを使用:変数は解析されず、そのまま出力される
literal_greeting='Hello, $name!'

echo $greeting        # 出力: Hello, Alice!
echo $literal_greeting # 出力: Hello, $name!

2. 変数の値へのアクセス

バリアブルに格納された値にアクセス(読み取り)するには、変数名の直前にドル記号 ($) を使用します。

基本構文:

$variable_name

また、変数名を中括弧 ({}) で囲むこともできます。これは、変数の値を周囲の他のテキストと密接に連結させる必要がある場合や、Bashの解析における曖昧さを回避したい場合に特に有効です。

中括弧構文:

${variable_name}

例:

name="Bob"
echo $name   # 出力: Bob
echo ${name} # 出力: Bob

# 中括弧を使用して変数名と後ろの感嘆符を区切り、Bashが「name!」という変数を探すのを防ぐ
greeting="Hello, ${name}!"
echo $greeting # 出力: Hello, Bob!

filename="my_file"
echo "完全なファイル名は: ${filename}.txt" # 出力: 完全なファイル名は: my_file.txt

2.1 変数の連結 (Concatenation)

複数のバリアブルを簡単に連結して、新しい文字列を作成できます。

例:

first_name="Charlie"
last_name="Brown"
full_name="$first_name $last_name" # 間にスペースを挿入
echo $full_name # 出力: Charlie Brown

2.2 特殊変数の復習

前章で触れた通り、Bashには定義済みの意味を持つ特殊変数がいくつかあります。ここで最も頻繁に使用されるものを復習しましょう:

  • $0: スクリプト自身の名称。
  • $1, $2...: スクリプトに渡された外部の位置パラメータ。
  • $#: スクリプトに渡された引数の総数。
  • $@: すべての引数をリスト(配列)として返します。
  • $?: 直前に実行されたコマンドの終了ステータス(0は成功、非0は失敗)。
  • $$: 現在のスクリプト実行時のプロセスID(PID)。

スクリプト例 (my_script.sh):

#!/bin/bash
echo "現在のスクリプト名: $0"
echo "渡された引数の総数: $#"
echo "すべての引数リスト: $@"
echo "実行中のプロセスID: $$"

もし bash my_script.sh arg1 arg2 arg3 を実行した場合、出力は以下のようになります:

現在のスクリプト名: my_script.sh
渡された引数の総数: 3
すべての引数リスト: arg1 arg2 arg3
実行中のプロセスID: 12345

3. 変数の破棄 (Unsetting Variables)

unset コマンドを使用して、バリアブルを削除(破棄)することができます。これにより、指定された変数は現在のシェル環境から完全に除去されます。バリアブルunset された後、それにアクセスしようとすると空の文字列が返されます。

構文:

unset variable_name

例:

my_variable="Some value"
echo $my_variable # 出力: Some value

unset my_variable
echo $my_variable # 出力: (空の文字列。何も表示されない)

3.1 Unset と空文字代入の違い

非常に重要な点として、unset は変数を完全に削除しますが、変数に空の文字列 "" を代入することは、その値を変更することに過ぎません。後者の場合、変数は依然として存在しており、その内容が空であるという状態を指します。

my_variable="Some value"
my_variable="" # 空文字を代入。変数は依然として存在する
unset my_variable # 完全に破棄。変数は存在しなくなる

特定の変数が定義されているかどうかを厳格にチェックする必要がある場合、この違いは極めて重要になります。テスト条件 [[ ]]-v オプションを使用すると、変数がセットされている(存在している)かどうかを確認できます。

ステータスチェック例:

my_variable="Some value"
if [[ -v my_variable ]]; then
  echo "my_variable はセットされています (存在します)"
fi
# 出力: my_variable はセットされています (存在します)

my_variable="" # 空文字を代入
if [[ -v my_variable ]]; then
  echo "my_variable は空ですが、セットされています (存在します)"
fi
# 出力: my_variable は空ですが、セットされています (存在します)

unset my_variable # 完全に破棄
if [[ -v my_variable ]]; then
  echo "セットされています"
else
  echo "my_variable はセットされていません (存在しません)"
fi
# 出力: my_variable はセットされていません (存在しません)

4. 変数スコープの概要

変数の「スコープ (Scope)」とは、スクリプト内でその変数にアクセス可能な領域を指します。Bashでは、デフォルトで変数はグローバルスコープ (Global scope) を持ちます。つまり、一度定義されると、スクリプト内のどこからでもアクセス可能です。しかし、関数 (Functions) を扱う場合(後のモジュールで詳述します)、ローカルスコープ (Local scope) を持つ変数を定義できます。これは、その関数内部からのみアクセス可能であることを意味します。本章では主にグローバルスコープに焦点を当てています。

5. 総合演習:システム情報の自動収集と表示

オートメーションによるシステム管理タスクのケーススタディに戻りましょう。学んだ変数の知識を活かして、サーバーのコアシステム情報を保存し、フォーマットして表示してみます。

#!/bin/bash

# コマンド置換を使用して情報を取得し変数に代入
hostname=$(hostname)
os=$(uname -s)
kernel_version=$(uname -r)
cpu_arch=$(uname -m)

# システム情報をフォーマットして表示
echo "=============================="
echo "    サーバーシステム情報レポート    "
echo "=============================="
echo "ホスト名: $hostname"
echo "オペレーティングシステム: $os"
echo "カーネルバージョン: $kernel_version"
echo "CPU アーキテクチャ: $cpu_arch"
echo "=============================="

このスクリプトは、コマンド置換 $(...) を巧みに利用して低レベルのシステムコマンドを実行し、その出力をカスタムバリアブルに安全に格納しています。その後、echo コマンドでこれらの変数を呼び出し、生のシステムデータを構造化された読みやすいレポートとしてコンソールに出力しています。