シェルスクリプトでtputを使ってターミナル出力を色分けする設計|ANSIコード直書きを避けて可搬性の高いカラー出力を実装する方法

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > シェルスクリプト > シェルスクリプトでtputを使ってターミナル出力を色分けする設計|ANSIコード直書きを避けて可搬性の高いカラー出力を実装する方法
「シェルスクリプトのエラーログを赤く表示させたい」「バックアップ完了を緑で知らせたい」と思い、`\e[31m` などの ANSI エスケープコードを直書きした経験はないでしょうか。手軽に動作するのは確かですが、このやり方にはターミナルエミュレータへの依存と、cronやパイプで実行したときに制御コードがそのまま出力に残るという問題があります。

この記事では、Linuxの tput コマンドを使ったカラー出力ライブラリの設計方法を解説します。ANSI 直書きより可搬性が高く、非対話環境でも安全に動くフォールバック設計まで、RHEL 9.4 / Ubuntu 24.04 LTS で動作確認した実装パターンを一通り紹介します。

この記事のポイント

・ tput は terminfo を参照して端末種別ごとに適切なエスケープコードを生成する
・ カラー変数をスクリプト冒頭に宣言し、log_error 等の関数に集約して再利用する
・ [ -t 1 ] と tput colors で非対話環境を検出し、色変数を空文字にしてクリーンな出力を保つ
・ trap で EXIT 時に必ずリセットシーケンスを送り、プロンプト着色を防ぐ


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜ ANSI 直書きを避けて tput を使うのか

ANSI エスケープコード(\e[31m 等)を直書きすると、次の2つの問題が発生することがあります。

・ ターミナル非対応環境での文字化け:一部のシリアルコンソールや最小インストールコンテナではANSIシーケンスが解釈されず、制御文字がそのままテキスト表示される
・ 非対話実行時の汚染:cron・パイプ・ファイルリダイレクト経由で実行したとき、エスケープコードがそのまま出力に混入し、grep によるログ解析を妨げる

tput コマンドは terminfo(端末能力データベース)を参照して、$TERM 変数に応じた正しいエスケープシーケンスを返します。スクリプト側でエスケープコードをハードコードする必要がなくなり、ターミナル種別の違いをシステムに吸収させられます。

# ANSI コードの直書き(非推奨) echo -e "\e[31mERROR: ディスク容量不足\e[0m" # tput を使った書き方(推奨) RED=$(tput setaf 1) RESET=$(tput sgr0) echo "${RED}ERROR: ディスク容量不足${RESET}"

tput コマンドの基本|色番号・スタイル・リセットの仕組み

1. 利用可能色数の確認と setaf による文字色指定

まず、ターミナルが何色に対応しているかを確認します。

$ tput colors 256

256 と表示された場合は 256 色対応です。8 未満の値の場合は標準 8 色のみです。

文字色を指定する tput setaf N の色番号(標準 8 色)は以下の通りです。

・ 0:黒(Black)
・ 1:赤(Red)— エラー表示に使う
・ 2:緑(Green)— 成功表示に使う
・ 3:黄(Yellow)— 警告表示に使う
・ 4:青(Blue)
・ 5:マゼンタ(Magenta)
・ 6:シアン(Cyan)— 情報表示に使う
・ 7:白(White)

背景色を変えたい場合は tput setab N を使います。256 色対応端末では色番号 0 から 255 の範囲が利用できます。

2. 太字・下線などのテキストスタイル

色以外に以下のスタイルが指定できます。

・ tput bold:太字
・ tput dim:薄いテキスト(暗い)
・ tput smul / tput rmul:下線開始 / 下線終了
・ tput rev:反転表示(前景と背景の色を入れ替える)

# 組み合わせ例(黄色の太字) echo "$(tput setaf 3)$(tput bold)WARNING: 重要な警告$(tput sgr0)" echo "$(tput smul)アンダーラインテキスト$(tput rmul)"

3. sgr0 でリセットする

色やスタイルを適用した後は必ず tput sgr0 でリセットします。リセットを忘れると、以降のすべての出力が同じ色・スタイルで表示され続けます。

tput sgr0 はすべての属性(色・太字・下線・反転等)を一括でリセットする命令です。\e[0m と同等ですが、端末種別に依存しないため運用環境を問わず安全に使えます。

カラー出力ライブラリの設計|log_error・log_success 関数を作る

1. カラー変数を宣言する

スクリプトの先頭でカラー変数を宣言しておくと、関数内で何度でも再利用できます。関数のたびに tput setaf を呼ぶと実行コストがかかるため、変数化しておくのが実務上の基本パターンです。

# カラー変数(スクリプト冒頭で宣言) RED=$(tput setaf 1) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3) CYAN=$(tput setaf 6) BOLD=$(tput bold) RESET=$(tput sgr0)

変数名をアッパーケースにすることでスクリプト内の定数として明示します。

2. ログレベル別の出力関数を定義する

カラー変数を使ったログ関数を定義することで、本体ロジックでは log_error "メッセージ" と書くだけになり、色の制御が本体ロジックから分離されます。

log_info() { echo "${CYAN}[INFO]${RESET} $*"; } log_ok() { echo "${GREEN}[OK]${RESET} $*"; } log_warn() { echo "${YELLOW}[WARN]${RESET} $*" >&2; } log_error() { echo "${RED}${BOLD}[ERROR]${RESET} $*" >&2; }

WARN / ERROR は標準エラー出力(>&2)に送ることで、ログファイルとエラーストリームを分けて扱えます。

実機(RHEL 9.4)でのターミナル実行例:

$ log_info "バックアップ開始: /var/www/html" [INFO] バックアップ開始: /var/www/html $ log_ok "完了: /backup/html_20261012.tar.gz" [OK] 完了: /backup/html_20261012.tar.gz $ log_warn "/backup の使用率が 85% を超えています" [WARN] /backup の使用率が 85% を超えています $ log_error "rsync が終了コード 23 で失敗しました" [ERROR] rsync が終了コード 23 で失敗しました

ターミナルでは [INFO] がシアン、[OK] が緑、[WARN] が黄、[ERROR] が赤の太字で表示されます。

カラー出力設計を含む実践的なシェルスクリプト技術については、シェルスクリプト実践ガイドでも詳しく解説しています。

非対話環境でのフォールバック設計|cron やパイプで色コードが混入しないようにする

ここが tput を使ったカラー出力設計の核心です。cron 実行時やパイプ先に渡す出力では、色コードがテキストとして混入します。これを防ぐフォールバック設計を組み込みます。

1. [ -t 1 ] で端末かどうかを判定する

Bash の [ -t N ] テストは、ファイルディスクリプタ N が端末(TTY)に接続されているかを判定します。

・ -t 0:標準入力が端末に接続されているか
・ -t 1:標準出力が端末に接続されているか
・ -t 2:標準エラー出力が端末に接続されているか

# 標準出力が端末かどうかを判定 if [ -t 1 ]; then echo "対話ターミナルで実行中" else echo "パイプまたはリダイレクト中(cron を含む)" fi

cron では標準出力がメール送信用パイプに接続されるため、[ -t 1 ] は偽になります。

2. TERM 環境変数と tput colors によるチェック

$TERM が未設定または "dumb" の場合、tput が正しく動作しません。より確実な方法として、tput colors の終了コードで判定します。

# tput が使用可能かチェック(終了コード 0 かつ色数が 8 以上か) if tput colors 2>/dev/null && [ "$(tput colors)" -ge 8 ]; then echo "カラー出力を有効化" else echo "カラーなしで実行" fi

3. ライブラリへのフォールバック組み込み

端末判定に応じてカラー変数を空にするフォールバック付きのライブラリ全体を以下に示します。color_lib.sh として保存し、他のスクリプトから source して使います。

#!/bin/bash # color_lib.sh - tput カラー出力ライブラリ(フォールバック対応版) # 対話ターミナルかつ tput が使えるときだけカラーを有効化 if [ -t 1 ] && tput colors 2>/dev/null && [ "$(tput colors)" -ge 8 ]; then RED=$(tput setaf 1) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3) CYAN=$(tput setaf 6) BOLD=$(tput bold) RESET=$(tput sgr0) else # 非対話環境ではすべて空文字にしてクリーンな出力を維持 RED="" GREEN="" YELLOW="" CYAN="" BOLD="" RESET="" fi log_info() { echo "${CYAN}[INFO]${RESET} $*"; } log_ok() { echo "${GREEN}[OK]${RESET} $*"; } log_warn() { echo "${YELLOW}[WARN]${RESET} $*" >&2; } log_error() { echo "${RED}${BOLD}[ERROR]${RESET} $*" >&2; }

カラー変数を空文字にすることで、判定ロジックを関数の外に出し、関数本体をシンプルに保てます。log_error 等の関数自体はコードを変更しなくてもよいため、ライブラリを読み込む側のスクリプトは環境に関係なく同一コードを使い回せます。

注意:POSIX シェル(/bin/sh)で使う場合は 2>/dev/null を明示してください(bash 拡張の &> は使えません)。

実践:バックアップスクリプトへの組み込み

color_lib.sh を実際のバックアップスクリプトに組み込む例を示します。

#!/bin/bash set -euo pipefail # カラーライブラリを読み込む source /usr/local/lib/color_lib.sh # EXIT 時に必ずリセットシーケンスを送る(プロンプト着色の防止) trap 'printf "%s" "${RESET}"' EXIT BACKUP_SRC="/var/www/html" BACKUP_DEST="/backup" TIMESTAMP=$(date +%Y%m%d_%H%M%S) OUTFILE="${BACKUP_DEST}/html_${TIMESTAMP}.tar.gz" log_info "バックアップ開始: ${BACKUP_SRC}" if tar -czf "${OUTFILE}" "${BACKUP_SRC}" 2>/dev/null; then SIZE=$(du -sh "${OUTFILE}" | cut -f1) log_ok "完了: ${OUTFILE} (${SIZE})" else log_error "tar が失敗しました(終了コード: $?)" exit 1 fi

ターミナルからの実行では色付きログが表示され、cron からの実行ではプレーンテキストでログファイルに書き出されます。

cron 実行ログの出力例(/var/log/backup.log より抜粋・RHEL 9.4 実機確認):

# /var/log/backup.log(cron 実行・色コードなし) [INFO] バックアップ開始: /var/www/html [OK] 完了: /backup/html_20261012_020001.tar.gz (124M)

set -euo pipefail と組み合わせることで、tar が途中で失敗した場合も log_error が確実に呼ばれ、問題箇所を素早く特定できます。

トラブルシュート|色が出ない・tput エラーのよくある原因と対処

「tput: No value for $TERM and no -T specified」が出る

$TERM 変数が設定されていない環境(Docker 最小イメージ・SSH 直接コマンド実行等)で発生します。

・ 対処 1:環境変数を明示する

export TERM=xterm-256color

・ 対処 2:-T オプションでターミナル種別を直接指定する

RED=$(tput -T xterm-256color setaf 1)

256 色を指定したのに 8 色しか表示されない

端末が 256 色対応でも $TERM が xterm(256 なし)になっていると 8 色のみになります。

# 確認 echo $TERM # xterm-256color になっているか tput colors # 256 が表示されれば OK # 修正 export TERM=xterm-256color

スクリプト終了後もシェルプロンプトが着色されたまま

スクリプト内で tput sgr0(または $RESET)を出力せずに終了すると発生します。実務では trap を使って確実にリセットするのが鉄則です。

# スクリプト冒頭に追加しておくと終了時に必ずリセットされる trap 'printf "%s" "${RESET}"' EXIT

printf "%s" を使うのは、echo の一部の実装が改行を付け足すためです。

本記事のまとめ

tput を使ったカラー出力ライブラリの設計ポイントをまとめます。

設計ポイント 内容
カラー変数 RED=$(tput setaf 1) 等をスクリプト冒頭で宣言する
ログ関数 log_info / log_ok / log_warn / log_error 関数に色指定を集約する
フォールバック [ -t 1 ] と tput colors で非対話環境を検出し、色変数を空文字にする
WARN/ERROR の出力先 >&2 で標準エラーに分ける(ログとの混在を防ぐ)
リセット忘れ防止 trap 'printf "%s" "${RESET}"' EXIT をスクリプト冒頭に追加する

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、tput を活用したカラー出力設計のような実践的なシェルスクリプト技術を体系的に学べる環境を用意しています。

>> シェルスクリプト実践ガイドを見る

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。