プロンプトの色を変える\[\033[01;34m\]ってなんだ?


はじめに

この記事は

既にある優れた記事などを読んで、自分で理解したこと&試したことをまとめました。
「手っ取り早く色変えたいんだよ!」という方は参考記事をご覧ください。

動機

毎回新しい環境を作るたびにググってたので、いいかげんちゃんと調べようと…

検証環境

Acer Chromebook 11 CB311-8H-C5DVのcrouton(crosh)とcrostini(標準ターミナル)。どっちもDebian(stretch)。

結論

\[ ... \]とは

bashプロンプトで使用できる特殊文字

\[
非表示文字のシーケンスの開始。 これを使うと、プロンプト中に端末の制御シーケンスを埋め込むことができます。
\]
非表示文字のシーケンスを終了します。

参考:

\033[01;34mとは

ANSI escape codeの中でCSI(Control Sequence Introducer) sequencesに含まれるSGR (Select Graphic Rendition) の指定(今回のメイン)

参考:

まずは\[ ... \]を消せ!

Linuxを触り始めて慣れてくると「プロンプトのデザイン変えたろ!」という欲求はだれもが持つものでしょう。
そしておもむろに~/.bashrcなどを開き、


PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

みたいな記述を見た瞬間「あっ、とりあえずコピペでいいや…」となったことでしょう(反省)。

そんなだらしない自分から脱却するため、今回ちゃんと調べてみました!
差し当たって、初見でやる気を削いでくるこの妙ちくりんな記述を分解してみます。

上の「結論」でも述べたとおり、\[\033[01;34m\]\[ ... \]\033[01;34mに別れます。
そして\[ ... \]は上述の通り非表示文字のシーケンスを表しますが、少なくとも私の環境ではなくても何の問題もありませんでした。ので、こいつは思い切って削除しちゃってもいいと思います。
推測ですが、カラーに対応していないターミナルアプリケーションなんかの場合に\033[01;34mが文字列として出力されるのを防ぐため(JavaScriptをHTMLのコメントで囲うみたいな?)かなーと考えましたが、~/.bashrcでは以下のような処理で振り分けてますし、正直存在意義が分かりません。お前のせいで見づらかったんだよ!

.bashrc
if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi

さぁ、これで残りは\033[01;34mだけ!だいぶ分かりやすく…なってない😓

\033ってなんだ?

ずばりエスケープシーケンス(の一部)です。
エスケープシーケンスといえば、例えばC言語でハローワールドする以下のコードの、

#include <stdio.h>
int main(){
        printf("Hello, World!\n");
}

\nもエスケープシーケンスです。
改行の場合には"n"という愛称文字が当てられていますが、改行を表す文字コードを記述しても同様に動作するのはご存知の通りでしょう。

#include <stdio.h>
int main(){
        printf("Hello, World!\n");
        printf("Hello, World!\x0A"); // 16進数
        printf("Hello, World!\012"); // 8進数
}

そうです、お気づきの通り\033も何らかの意味を持つ文字コードを8進数で記述したものなのです。
そしてその意味はアスキーコード表などを見ればすぐ分かりますが、
ESC(エスケープ)です。
まんまやん!エスケープシーケンスだからね!
となると当然「改行は\n」のように愛称文字があるのではないかという疑問が湧くと思いますが、
\eです。
まんまやん!ESCのeね!

という訳で\033[01;34m\e[01;34mと書き換えられます。またちょっと見やすくなりました。

\e[...mの構文で記述する

で、まとめるとフォントの色やスタイルの指定は\e[...mの構文で記述することになっています。
ここでパラメーターは;で区切って複数併記することができます。
従って繰り返し登場している\e[01;34mは、
\e[01m:ボールド(bold)をセット

\e[34m:フォアグラウンドを青にセット
に分解できます。
指定できるパラメーターは参考記事やMan page of CONSOLE_CODESをご覧ください。

プロンプトだけじゃない!

greplsコマンドでもフォントカラーが変わったりするので、考えれば当然なのですが、例えば以下のようにターミナルで変数に代入する場合にも使えたりします。

$ var='\e[41mH\e[42mE\e[43mL\e[44mL\e[45mO\e[46m!\e[m'
$ echo -e $var

実行結果

ちなみにechoコマンドでエスケープシーケンスを解釈させるには-eオプションを付けます。

-e バックスラッシュによるエスケープを解釈する

256色指定

色関連であといくつか。
ESC[ 38;5;⟨n⟩ m:foreground color
ESC[ 48;5;⟨n⟩ m:background color

の構文で256色の指定ができます。nの数字と色の対応は以下の通り。

0- 7: standard colors (as in ESC [ 30–37 m)
8- 15: high intensity colors (as in ESC [ 90–97 m)
16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
232-255: grayscale from black to white in 24 steps

参考:ANSI escape code - Wikipedia

実行してみるとこんな感じ。

color_256.sh
#!/bin/bash

for i in {0..15}
do 
  for j in {0..15}
  do  
    ((c = i * 16 + j)) 
    printf "\e[38;5;%dm%02X " $c $c  
  done
  echo ""
done

rgb(トゥルーカラー)指定

ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m:Select RGB foreground color
ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m:Select RGB background color

せっかくなのでグラデーションを作ってみました。

color.sh
#!/bin/bash

for r in {32..0}
do
        ((b = 32 - r ))
        for g in {0..32}
        do
                printf "\e[48;2;%d;%d;%dm  " $((r<<3)) $((g<<3)) $((b<<3))
        done
        echo ""
done

もういっちょ。

color2.sh
#!/bin/bash

rgb_curve(){

    x=$1
    ((x %= 192))
    if (($1 < 0)); then
        ((x += 192))
    fi

    if ((x <= 0)); then
        return 0
    elif ((x < 32)); then
        return $(((x << 3) - 1))
    elif ((x < 96)); then
        return $(((16 << 4) - 1))
    elif ((x < 128)); then
        return $((((128 - x) << 3) - 1))
    elif ((x < 192)); then
        return 0
    fi
}

for i in {1..32}
do
    for j in {-32..160}
    do
        rgb_curve $((j - 64)); r=$?
        rgb_curve j; g=$?
        rgb_curve $((j + 64)); b=$?
        printf "\e[48;2;%d;%d;%dm " $r $g $b
    done
    echo ""
done

echo -e "\e[m"

もうちょっと関数キレイにしたいですね…

以上!

参考記事