第13章 シェル環境のカスタマイズとシェルスクリプト入門

LPIC-1 105.1 / 105.2 相当

毎回同じ設定をやり直さずに済むよう、シェルの環境をカスタマイズする方法と、コマンドを自動化するシェルスクリプトの基本を学びます。

bashの設定ファイル

ファイル読み込まれるタイミング
~/.bash_profile / ~/.bash_login / ~/.profileログインシェル起動時(例: SSHログイン直後)
~/.bashrc対話的な非ログインシェル起動時(例: ターミナルを新しく開いたとき)

ここに alias や export を書いておくと、毎回自動的に設定が反映されます。

# ~/.bashrc に追記する例
alias ll='ls -l'
alias ..='cd ..'
alias grep='grep --color=auto'
export EDITOR=vim
export PATH="$HOME/bin:$PATH"

編集後は、ファイルを再読み込みすることですぐに反映できます。

$ source ~/.bashrc      # . ~/.bashrc でも同じ意味

aliasとexportの違いも整理しておきましょう。aliasはコマンドの「別名」を定義するだけのシェル機能で、そのシェル内でしか有効になりません。一方exportで設定した環境変数は、そのシェルから起動される子プロセス(スクリプトや別のプログラム)にも引き継がれます。exportを付けずに変数を代入しただけでは、シェル変数としてそのシェル内でしか使えず、子プロセスには渡りません。

$ MYVAR="hello"        # シェル変数(このシェル内だけで有効)
$ export MYVAR         # 環境変数に昇格。以後起動する子プロセスにも引き継がれる
$ export MYVAR2="world" # 代入とexportを1行でまとめて書くことも可能
$ unset MYVAR           # 変数の定義を削除
$ env | grep MYVAR2     # envコマンドで現在の環境変数一覧を確認
MYVAR2=world

この行のこの値に注目: env | grep MYVAR2の結果にMYVAR2=worldが表示されれば、そのシェルの環境変数として正しく登録されていることが確認できます。unsetしたMYVARはこの一覧にもenv全体にも現れません。

試験対策: ログインシェルの起動順序は「/etc/profile → ~/.bash_profile(あれば。なければ~/.bash_login、それもなければ~/.profile)」の順です。~/.bashrcは慣習として~/.bash_profileの中から明示的にsourceされることが多く、ディストリビューションによって細部の実装は異なります。

シェルスクリプトの基本

1行目の #!/bin/bash は「シバン(shebang)」と呼ばれ、このスクリプトをどのプログラムで実行するかを指定します。

#!/bin/bash
# backup.sh: 簡単なバックアップスクリプト
TARGET_DIR="/home/user/docs"
BACKUP_NAME="backup-$(date +%Y%m%d).tar.gz"

if [ -d "$TARGET_DIR" ]; then
  tar -czf "$BACKUP_NAME" "$TARGET_DIR"
  echo "バックアップ完了: $BACKUP_NAME"
else
  echo "ディレクトリが見つかりません: $TARGET_DIR"
  exit 1
fi
$ chmod +x backup.sh   # 実行権限を付与(正常時は無出力)
$ ./backup.sh          # カレントディレクトリのスクリプトを実行
バックアップ完了: backup-20260820.tar.gz

この行のこの値に注目: 表示されるバックアップ完了: backup-20260820.tar.gzは、スクリプト内のecho行がそのまま出力されたものです。/home/user/docsが存在しない場合は、else節の「ディレクトリが見つかりません」が表示され、終了ステータスも1(異常終了)になります。

基本的な制御構文

# for ループ
for f in *.txt; do
  echo "処理中: $f"
done

# while ループ
count=1
while [ $count -le 3 ]; do
  echo "$count 回目"
  count=$((count + 1))
done

# until ループ(条件が真になるまで繰り返す。whileの逆)
count=1
until [ $count -gt 3 ]; do
  echo "$count 回目"
  count=$((count + 1))
done

# case文(複数の条件分岐をif/elifより簡潔に書ける)
case "$1" in
  start)
    echo "起動します"
    ;;
  stop)
    echo "停止します"
    ;;
  *)
    echo "使い方: $0 {start|stop}"
    ;;
esac

スクリプトの終了ステータスは $? で確認できます。0 は正常終了、それ以外はエラーを意味する慣習です。&&(前のコマンドが成功したら実行)や||(前のコマンドが失敗したら実行)と組み合わせることで、if文を使わずに簡易的な条件分岐を書くこともできます。

$ mkdir backup && echo "作成成功"
作成成功
$ ls missing.txt || echo "ファイルが見つかりません"
ls: cannot access 'missing.txt': No such file or directory
ファイルが見つかりません

この行のこの値に注目: 1つ目はmkdirが成功(終了ステータス0)したため&&の右側が実行され「作成成功」が表示されます。2つ目はlsがエラーで失敗(終了ステータス非0)したため、まずls自身のエラーメッセージが表示され、続けて||の右側の「ファイルが見つかりません」も表示されます。

testコマンドと条件式

if文の[ 条件 ]は、実はtestコマンドの別記法です。よく使う判定演算子を覚えておくと読み書きがスムーズになります。

演算子意味
-e ファイルファイルが存在する
-f ファイル通常ファイルとして存在する
-d ファイルディレクトリとして存在する
-z 文字列文字列が空である
文字列1 = 文字列2文字列が等しい
数値1 -eq 数値2数値が等しい(他に -ne, -lt, -gt, -le, -ge)
#!/bin/bash
if [ -f "$1" ]; then
  echo "$1 はファイルです"
elif [ -d "$1" ]; then
  echo "$1 はディレクトリです"
else
  echo "$1 は存在しません"
fi

位置パラメータと関数

スクリプトに渡された引数は$1、$2...として参照できます。まとまった処理は関数として切り出すと再利用しやすくなります。

変数意味
$1, $2...1番目、2番目...の引数
$0スクリプト自身の名前
$#引数の個数
$@すべての引数(個別の単語として展開)
#!/bin/bash
greet() {
  echo "こんにちは、$1さん"
  return 0
}

greet "$1"
echo "引数の数: $#"
試験対策: シェルスクリプト内で使う変数は、意図しない単語分割やパス展開を防ぐため "$1" のようにダブルクォートで囲む習慣をつけましょう。特にスペースを含むファイル名を扱う際に重要です。

コマンド置換と算術演算

あるコマンドの実行結果を、別のコマンドの引数や変数として使いたい場合はコマンド置換を使います。書式は$(コマンド)で、バッククォート(`コマンド`)による古い書式より読みやすく、ネスト(入れ子)もしやすいため現在はこちらが推奨されます。

$ today=$(date +%Y%m%d)
$ echo "今日は $today です"
今日は 20260815 です
$ count=$(ls *.txt | wc -l)     # txtファイルの個数を数えて変数に代入

数値の計算には$(( ))という算術式展開を使います。bashの変数はデフォルトではすべて文字列として扱われるため、単純に+で連結しようとしても数値の足し算にはならない点に注意が必要です。

$ a=5
$ b=3
$ echo $((a + b))
8
$ echo $((a * b))
15
$ echo $((a % b))    # 剰余(あまり)
2

よくある間違い

間違いの例問題点・正しい書き方
if [$a -eq 1]角括弧の内側と外側にスペースが必要。正しくは if [ $a -eq 1 ]
if [ $name = "" ]($nameが未設定)変数展開が空文字になり構文エラーになりやすい。if [ -z "$name" ]やif [ "$name" = "" ]のようにダブルクォートで囲む
result = $((1+2))代入時は = の前後にスペースを入れない。正しくは result=$((1+2))

これらはいずれも「bashはスペースの有無で構文の解釈が変わる」という特徴に起因するミスです。エラーメッセージが分かりにくい場合も多いため、まずはスペースの位置を疑ってみるとよいでしょう。

スクリプトを安全に書くための3点セット

ある程度の規模のシェルスクリプトを書くようになったら、冒頭に次の1行を加える習慣をつけておくと、多くの事故を未然に防げます。

#!/bin/bash
set -euo pipefail
オプション効果
-e途中のコマンドが失敗(終了ステータス0以外)した時点でスクリプトを即座に停止する
-u未定義の変数を参照しようとした時点でエラーにする(変数名のタイプミスに気づきやすくなる)
pipefailパイプでつないだ処理のうち、途中のコマンドが失敗した場合もスクリプト全体の失敗として扱う

これらを付けずに書いたスクリプトは、途中でエラーが起きても気づかないまま後続の処理が実行され続けてしまうことがあります。特に本番環境に影響する自動化スクリプトでは、「失敗したら即座に止まる」という性質は事故防止の観点から非常に重要です。

関数の戻り値とexitコードの扱い

シェルスクリプトの関数は、他のプログラミング言語のように値を直接returnするのではなく、returnで指定した数値がそのまま「終了ステータス」として扱われる点に注意が必要です。文字列や複雑なデータを返したい場合は、echoで出力してコマンド置換$(関数名)で受け取る、という回りくどい書き方が必要になります。この違いを知らずに関数の戻り値を数値以外で使おうとすると、意図しない動作になりがちなので、「returnは成否(0か非0か)を返すためのもの」と割り切って理解しておくとよいでしょう。

確認クイズ

Q1. ~/.bashrc が読み込まれるタイミングとして正しいものはどれですか?

解説: ~/.bashrc は対話的な非ログインシェル(例: 新しいターミナルウィンドウ)を開いたときに読み込まれます。ログインシェルでは~/.bash_profileなどが使われます。

Q2. シェルスクリプトの1行目に書く #!/bin/bash の役割はどれですか?

解説: #!で始まる1行目はシバンと呼ばれ、このファイルをどのインタプリタで実行するかを指定します。

Q3. 編集した ~/.bashrc の内容を、ログインし直さずにすぐ反映させるコマンドはどれですか?

解説: source(または . コマンド)で設定ファイルを再読み込みすると、ログインし直さなくても変更がすぐ反映されます。

Q4. スクリプトファイルを ./script.sh の形で実行するために、事前に必要な操作はどれですか?

解説: スクリプトを直接実行するには、chmod +x で実行権限を付与しておく必要があります。