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

## はじめに

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

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

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

### 結論
#### `\[ ... \]`とは
bashプロンプトで使用できる特殊文字
> \\[
非表示文字のシーケンスの開始。 これを使うと、プロンプト中に端末の制御シーケンスを埋め込むことができます。
\\]
非表示文字のシーケンスを終了します。

参考：

- <a href="https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html">Man page of BASH</a>

#### `\033[01;34m`とは
ANSI escape codeの中でCSI(Control Sequence Introducer) sequencesに含まれるSGR (Select Graphic Rendition) の指定(今回のメイン)

参考：

- [ANSI escape code \- Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code)
- [Man page of CONSOLE\_CODES](https://linuxjm.osdn.jp/html/LDP_man-pages/man4/console_codes.4.html#lbAD)

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

```bash

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`では以下のような処理で振り分けてますし、正直存在意義が分かりません。お前のせいで見づらかったんだよ！

```bash:.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言語でハローワールドする以下のコードの、

```c
#include <stdio.h>
int main(){
        printf("Hello, World!\n");
}
```
`\n`もエスケープシーケンスです。
改行の場合には"n"という愛称文字が当てられていますが、改行を表す文字コードを記述しても同様に動作するのはご存知の通りでしょう。

```c
#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](https://linuxjm.osdn.jp/html/LDP_man-pages/man4/console_codes.4.html#lbAD)をご覧ください。

## プロンプトだけじゃない！
`grep`や`ls`コマンドでもフォントカラーが変わったりするので、考えれば当然なのですが、例えば以下のようにターミナルで変数に代入する場合にも使えたりします。

```bash
$ var='\e[41mH\e[42mE\e[43mL\e[44mL\e[45mO\e[46m!\e[m'
$ echo -e $var
```
実行結果
![Screenshot 2019-10-15 at 01.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378557/a317b97b-dc3c-133c-e6b7-edce45c41258.png)

ちなみに`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](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit)

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

```shell: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
```
![Screenshot 2019-10-15 at 01.25.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378557/84cb111d-bec0-ecd5-01f2-d9b9d0cf676b.png)

## rgb(トゥルーカラー)指定
`ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m`:Select RGB foreground color
`ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m`:Select RGB background color

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

```shell: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
```
![Screenshot 2019-10-15 at 01.34.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378557/27d2f81f-3eda-e73a-b4d0-1019971d96e2.png)

もういっちょ。

```shell: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"
```
![Screenshot 2019-10-15 at 01.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378557/551a9972-abc9-453d-2168-ede0a0b96fd4.png)


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


以上！

## 参考記事

- Qiita記事
    - [Bashのプロンプトに色を付けてサーバやユーザを区別する \- Qiita](https://qiita.com/fernet/items/4dcb6f82520d87227121)
    - [Bashプロンプトの変更 \- Qiita](https://qiita.com/zaburo/items/9194cd9eb841dea897a0)
    - [ANSIエスケープシーケンス チートシート \- Qiita](https://qiita.com/PruneMazui/items/8a023347772620025ad6)
- [ANSIエスケープコード \- コンソール制御 \- 碧色工房](https://www.mm2d.net/main/prog/c/console-02.html)
    - 大変参考になりました。ターミナルで画像のプレビューやってみたい。
- [サーモグラフィ風の色変化をシグモイド関数で再現する \- Qiita](https://qiita.com/masato_ka/items/c178a53c51364703d70b)
    - color2.shで雰囲気だけ参考にしました。shellscriptでは無理だ…。
- その他
    - [ANSI escape code \- Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code#See_also#SGR_parameters)
    - [Man page of BASH](https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html)
    - [Man page of CONSOLE\_CODES](https://linuxjm.osdn.jp/html/LDP_man-pages/man4/console_codes.4.html#lbAD)