はじめに

こんにちは!今回はsetコマンドについて解説します。

setは、シェルの動作を制御するためのコマンドです。特にシェルスクリプトでエラー処理を厳密にしたり、デバッグしたりする時に超重要です。

setコマンドとは

setは、シェルのオプションや位置パラメータを設定する組み込みコマンドです。

例えば、「エラーが起きたらスクリプトを止める」とか「未定義の変数を使ったらエラーにする」とか、シェルの挙動を細かく制御できます。プロのシェルスクリプトには必須のコマンドです。

基本構文

1
set [オプション] [引数...]

主なオプション

オプション 説明
-e コマンドがエラーで終了したらスクリプトを終了
-u 未定義変数を使用したらエラー
-x 実行するコマンドを表示(デバッグ用)
-o pipefail パイプライン内のコマンドが失敗したら全体を失敗扱い
-v 入力行を読み込んだら表示
-n コマンドを読むだけで実行しない(構文チェック)
+オプション オプションを無効化(例: +xでデバッグ表示をオフ)

使用例

例1: エラーで即座に終了する(-e)

1
2
3
4
5
6
#!/bin/bash
set -e

echo "Step 1"
false  # このコマンドは失敗する
echo "Step 2"  # ここは実行されない

実行結果:

1
Step 1

set -eを使うと、エラーが起きた時点でスクリプトが停止します。これで問題のあるまま処理が進むのを防げます。

例2: 未定義変数をエラーにする(-u)

1
2
3
4
#!/bin/bash
set -u

echo "Name: $NAME"  # NAMEが定義されてないのでエラー

実行結果:

1
bash: NAME: 未定義の変数です

変数の typo とか防げるので便利です。

例3: 実行コマンドを表示する(-x)

1
2
3
4
5
#!/bin/bash
set -x

NAME="Taro"
echo "Hello, $NAME"

実行結果:

1
2
3
+ NAME=Taro
+ echo 'Hello, Taro'
Hello, Taro

各コマンドの実行前に+付きで表示されます。デバッグに超便利。

例4: パイプラインのエラーを検出(-o pipefail)

1
2
3
4
5
#!/bin/bash
set -o pipefail

# 途中でエラーが起きても検出できる
cat non_existent_file.txt | grep "pattern" | sort

普通だとパイプラインの最後のコマンド(sort)の結果しか見ないけど、pipefailを使うと途中のエラーも検出できます。

例5: 複数のオプションを同時に設定

1
2
3
4
5
6
7
#!/bin/bash
set -euo pipefail

# これは推奨される設定
# -e: エラーで終了
# -u: 未定義変数でエラー
# -o pipefail: パイプラインのエラー検出

この3つの組み合わせは「安全なシェルスクリプト」の基本設定として有名です。

例6: デバッグモードのオン/オフ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

echo "通常モード"

set -x
echo "デバッグモード"
ls /tmp

set +x
echo "通常モードに戻る"

実行結果:

1
2
3
4
5
6
7
通常モード
+ echo デバッグモード
デバッグモード
+ ls /tmp
file1.txt file2.txt
+ set +x
通常モードに戻る

set +xで元に戻せます。

例7: 位置パラメータを設定

1
2
3
4
5
6
7
#!/bin/bash

set -- apple banana orange

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

実行結果:

1
2
3
第1引数: apple
第2引数: banana
第3引数: orange

--の後に指定した値が位置パラメータ($1, $2, $3…)に設定されます。

例8: 現在の設定を確認

1
set -o

実行結果:

1
2
3
4
5
allexport       off
braceexpand     on
emacs           on
errexit         off
...

現在のシェルオプションの状態が一覧表示されます。

よく使う組み合わせ

安全なスクリプトの基本設定

1
2
3
4
5
6
7
#!/bin/bash
set -euo pipefail

# これで以下が保証される:
# 1. エラーが起きたら即座に終了
# 2. 未定義変数を使ったらエラー
# 3. パイプライン内のエラーも検出

この設定は「Bash Strict Mode」として広く推奨されています。

デバッグ用の設定

1
2
3
4
5
#!/bin/bash
set -x

# すべてのコマンドが表示されるので
# どこで問題が起きてるか追跡しやすい

構文チェックのみ

1
2
3
4
5
#!/bin/bash
set -n

# コマンドを読むだけで実行しない
# スクリプトの文法チェックに使える

Tips・注意点

  • -eの落とし穴: if文やwhile文の中では-eが無効になる

    1
    2
    3
    4
    
    set -e
    if false; then  # ここではエラーにならない
      echo "This won't run"
    fi
    
  • エラーハンドリングとの併用: trapと組み合わせると強力

    1
    2
    
    set -e
    trap 'echo "Error on line $LINENO"' ERR
    
  • 一時的にオプションを変更: 必要な部分だけオンにできる

    1
    2
    3
    
    set +e  # エラーで止まらないようにする
    risky_command  # 失敗しても続行したい
    set -e  # また厳密モードに戻す
    
  • IFS(Internal Field Separator)の変更: setではなくIFS変数を直接設定

    1
    2
    
    # 空白ではなくカンマで分割したい時
    IFS=','
    
  • 位置パラメータのクリア: set --で全部クリアできる

    1
    2
    
    set -- apple banana
    set --  # $1, $2 などがクリアされる
    

実践的な使い方

本番環境用スクリプト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
set -euo pipefail

# エラーが起きたらメッセージ表示して終了
trap 'echo "Error on line $LINENO"; exit 1' ERR

# ここから本処理
echo "バックアップを開始します..."
cp /data/important.db /backup/
echo "完了しました"

エラーが起きた行番号も表示されるので、デバッグが楽です。

デバッグ用スクリプト

1
2
3
4
5
6
7
8
9
#!/bin/bash

# DEBUG環境変数が設定されてたらデバッグモード
if [ "${DEBUG:-}" = "true" ]; then
  set -x
fi

echo "処理を開始します"
# ... スクリプトの本体 ...

使い方:

1
2
3
4
5
# 通常実行
./script.sh

# デバッグモードで実行
DEBUG=true ./script.sh

配列を位置パラメータに展開

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

files=("file1.txt" "file2.txt" "file3.txt")

# 配列を位置パラメータに設定
set -- "${files[@]}"

# ループで処理
for file in "$@"; do
  echo "Processing: $file"
done

エラーが起きても続行したい場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
set -e

# この部分は失敗しても続行したい
set +e
optional_command || echo "Optional command failed, but continuing..."
set -e

# ここからは再び厳密モード
important_command

パイプラインのエラー検出

1
2
3
4
5
6
7
8
9
#!/bin/bash
set -o pipefail

# ログファイルからエラーを検索
# grepが見つからなかった場合(終了コード1)も検出される
if cat /var/log/app.log | grep "ERROR"; then
  echo "エラーが見つかりました"
  exit 1
fi

スクリプトの冒頭テンプレート

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash

# 安全な設定
set -euo pipefail

# エラーハンドラー
trap 'echo "Error: Script failed at line $LINENO"' ERR

# デバッグ用(必要に応じて)
# set -x

# ここからスクリプトの本体
echo "スクリプト開始"
# ...

この設定をテンプレートにしておくと、安全なスクリプトが書けます。

setとshoptの違い

shoptも似たようなコマンドですが、役割が違います。

1
2
3
4
5
6
7
# set: POSIXシェルの標準オプション
set -e
set -u

# shopt: Bash独自の拡張オプション
shopt -s nocaseglob  # 大文字小文字を区別しないグロブ
shopt -s dotglob     # .で始まるファイルもマッチ

基本的にはsetを使って、Bash特有の機能が欲しい時だけshoptを使います。

まとめ

今回はsetコマンドについて解説しました。

ポイント:

  • setでシェルの動作を制御できる
  • -eでエラー時即座に終了(推奨)
  • -uで未定義変数をエラーに(推奨)
  • -xでデバッグ表示(開発時に便利)
  • -o pipefailでパイプラインのエラー検出(推奨)
  • set -euo pipefailが安全なスクリプトの基本

シェルスクリプトを書く時は、最初にset -euo pipefailを書いておくのがおすすめです。エラーの早期発見につながって、バグが減ります。

次回もLinuxコマンドの学習を続けていきましょう!