シェルに色属性のエスケープシーケンスを格納した変数群を導入するワンライナー

  • 3
    いいね
  • 0
    コメント

シェルの出力に色をつけるためには色属性のエスケープシーケンスという特殊な文字を出力するとよいです。

$ echo -e "\e[033mhello\e[m"
hello

上だと hello の出力が黄色になります。

ただ、この書き方を覚えるのは大変なので、Qiita でもみなさん工夫している記事が多く見つかります。

類別してみると以下のようになります。

  • 色属性のエスケープシーケンスを列挙して Bash の変数にあらかじめ入れる
  • 他のプログラミング言語でライブラリを入れる
  • 色付けを支援する外部コマンドを導入する

どの工夫も良い解法なのですが、もうちょっと何とかしたいと感じました。

  • 色属性のエスケープシーケンスを列挙して Bash の変数にあらかじめ入れる
    • この変数群を用意するプログラムがそこそこ大きい(と言っても100行以下ですが)
    • 使い捨てみたいな感じで使うにはワンライナーくらいの素朴さにならないものか
  • 他のプログラミング言語でライブラリを入れる
    • レガシー環境でそのプログラミング言語がない場合がある
    • ライブラリを自由に入れられない環境もある
    • ライブラリが外部コマンドを入れてくれるならいいものの、シェルスクリプトで色付けしたい場合にそのプログラミング言語のクラスライブラリだけ提供されると少々手間
  • 色付けを支援する外部コマンドを導入する
    • 多種多様なサーバに入っていると、そこまで腰を据えて使うわけじゃないんだけど…と思う

あまりにも些細な不満かもしれませんが、問題意識は大事。

上の要望をまとめると

  • Bash に色属性のカラーシーケンスに対応した変数を導入してくれるくらいでいい
  • ワンライナーくらいになると嬉しい
  • 他のプログラミング言語を使うとしても、ほぼどこにでもあると仮定できるもの

こんな感じです。

そういえば、古今東西どの Linux ディストリビューションにも最初から入っているのが Perl で、2003年くらいの Perl 5.8 から Term::ANSIColor というコアモジュール(Perlインタプリタと同梱されて最初から使えるモジュール)があります。このモジュールは、まさにターミナルへの出力に色付けをするというもの。もちろん Term::ANSIColor も出力の色付けのために色属性のエスケープシーケンスを使っています。

Perl ではなく Bash シェルスクリプトを書く場合にも、この Term::ANSIColor が持っている色情報を活用できないものでしょうか。

というわけで書いてみました。

$ eval $( perl -MTerm::ANSIColor=:constants -E 'say qq($_="@{[ eval qq{$_} ]}") for @{$Term::ANSIColor::EXPORT_TAGS{constants}};' )

2003年リリースであるバージョン 5.8 以降の perl が使える環境だと、この一行で現在のシェルに $RED といった色属性のエスケープシーケンスを格納した変数群が用意されます。

現在のシェルから起動されるサブシェルやコマンドにも環境変数として渡して良い場合には export を付けます。

$ eval $( perl -MTerm::ANSIColor=:constants -E 'say qq(export $_="@{[ eval qq{$_} ]}") for @{$Term::ANSIColor::EXPORT_TAGS{constants}};' )

この perl ワンライナー自体は Term::ANSIColor から色名とその色属性のエスケープシーケンスの対を取り出してシェルの変数代入文を作って出力しています。それをシェルの eval を使って現在のシェルで評価しているだけです。実際にシェル eval を外して perl コマンドだけにするとわかりやすいです。

実際にどんな色変数を導入しているかは以下で確認できます。


$ perl -MTerm::ANSIColor=:constants -E 'say for @{$Term::ANSIColor::EXPORT_TAGS{constants}};'
CLEAR
RESET
BOLD
DARK
FAINT
ITALIC
UNDERLINE
UNDERSCORE
BLINK
REVERSE
CONCEALED
BLACK
RED
GREEN
YELLOW
BLUE
MAGENTA
CYAN
WHITE
ON_BLACK
ON_RED
ON_GREEN
ON_YELLOW
ON_BLUE
ON_MAGENTA
ON_CYAN
ON_WHITE
BRIGHT_BLACK
BRIGHT_RED
BRIGHT_GREEN
BRIGHT_YELLOW
BRIGHT_BLUE
BRIGHT_MAGENTA
BRIGHT_CYAN
BRIGHT_WHITE
ON_BRIGHT_BLACK
ON_BRIGHT_RED
ON_BRIGHT_GREEN
ON_BRIGHT_YELLOW
ON_BRIGHT_BLUE
ON_BRIGHT_MAGENTA
ON_BRIGHT_CYAN
ON_BRIGHT_WHITE

赤、青、黄色を表示して最後に色属性をリセットする場合、以下のように書けます。

$ echo "$RED$BLUE$YELLOW 黄色 $RESET"
 赤  青  黄色 

スクリーンショット 2016-09-01 20.26.01.png

もっとたくさんの種類の色を導入したい場合にも Term::ANSIColor が持っている情報を使うことができますが、ひとまず上記変数群がワンライナーで導入できるだけで嬉しい場面も多いでしょう。