【シェルスクリプト実践講座】ANSIエスケープシークエンスを使おう①〜基本的な使い方


2021/09/25
蛸壺の技術ブログ|ANSIエスケープシークエンスを使おう①〜基本的な使い方

これからシェルスクリプトをしっかり学んでいきたい方の中には、今後シェルプログラミングでちょっとしたコンソールアプリを作成したい時があるかも知れません。

シェルアプリを作成する上で欠かせないテクニックの核になるのが、
「ANSIエスケープシークエンス」と呼ばれるシステムで利用される特別な機能を利用することです。

今回はその基本操作について整理していきたいと思います。


基礎の基礎

シェルコマンドでエスケープシークエンスを呼び出すためには、echoコマンドに-eオプションを添えて定義された制御シークエンスを利用することになります。

            
            $ echo -e "<画面制御文>"
#👇Bash等のANSI-Cクォートが使える場合には以下でもOK
$ echo $'<画面制御文>'
        
エスケープシーケンスは、その名の通りエスケープ文字から始まる特殊制御文字列を端末に送ることで様々な機能・操作を行うことができます。

ちなみにLinuxではディストリビューション毎に標準搭載されているターミナルアプリケーションによって多少の挙動の違いがあります。

軒並みエスケープ文字は以下のどれか使えると思います。

            
            \e
\033
\x1b
        
最近のbashでは実際どちらでも動くと思いますので、どれを使って書いても構いません。

この記事では
\eをメインに使っていきます。

エスケープシークエンスの画面制御文字列はおおよそ以下のようなに大まかに3つの構成パートで記述される構文をしています。

            
            ___①    ____②   ____③
\e[      数字     文字
        
①の\e[がエスケープシークエンスが始まることを示すプレフィックスに当たる定型部です。

②は主に数字が指定されて使われることがほとんどですが、省略されたり、
;切りで数字が並ぶこともあります。

③は操作や制御の種類を識別するための文字が指定されます。

例えば、出力文字列をイタリックに表示を変えたい場合には以下を実行します。

            
            $ echo -e "\e[3m"
        
すると以下の図のように、このエスケープシークエンスが出力された以降の端末で持続的にイタリックの文字出力になっています。(※Zshではエスケープシークエンス出力はコマンドを実行する度に初期化されるので、bashのように状態が持続することはありません。)

合同会社タコスキングダム|蛸壺の技術ブログ

これをデフォルトの状態に戻す場合には

            
            $ echo -e "\e[0m"
        
とします。

合同会社タコスキングダム|蛸壺の技術ブログ

このエスケープシークエンスは一連した文字列の合間合間に挿入することもできます。

            
            $ echo -e "普通の文字列が...\e[3m一旦イタ リックになって\e[0m...また普通に戻ります。"
        
という部分的にイタリックに出力を変更したいコマンドを実行すると、

合同会社タコスキングダム|蛸壺の技術ブログ

というように利用することになります。


制御操作の作法

ここからはざっと操作の種類別にまとめてみます。

制御文字列の構成を再掲しますと、

            
            ___①    ____②   ____③
\e[      数字     文字
        
ということを念頭に以下表形式でエスケープシークエンスをまとめます。


文字種を変える

先程の例で文字をイタリック調に表示したりしてみましたが、文字の出力を変える操作には以下のようなものがあります。

操作・機能

m

0 or なし

リセット(デフォルトへ戻す)

m

1

太文字

m

2

薄く

m

3

イタリック

m

4

アンダーライン

m

5

点滅

m

6

高速点滅

m

7

文字と背景の色を反転

m

8

非表示

m

9

取消線


文字や背景に着色することも可能です。

端末エミュレータごとで、色を変更後にデフォルト値にリセットされる/そのまま色が維持されるなど挙動が少し異なるかも知れません。

とにかく処理の最後にリセットしたい場合には
\e[mを末尾にセットしておきましょう。

文字の色の変更

操作・機能

m

0;30 or 30

Black

m

0;31 or 31

Red

m

0;32 or 32

Green

m

0;33 or 33

Brown

m

0;34 or 34

Blue

m

0;35 or 35

Purple

m

0;36 or 36

Cyan

m

0;37 or 37

Light Gray

m

1;30

Dark Gray

m

1;31

Light Red

m

1;32

Light Green

m

1;33

Yellow

m

1;34

Light Blue

m

1;35

Light Purple

m

1;36

Light Cyan

m

1;37

White

m

38;5;N

色拡張①。調整量N(0~255)でカラーコードを指定

m

38;2;R;G;B

色拡張②。調整量R/G/B(各0~255)をRGBカラーコードで指定

色拡張の機能はもしかするとターミナルによっては対応してないかも知れません。

背景色の変更

背景色も基本的に文字色のルールとほぼ同じです。

操作・機能

m

0;40 or 40

Black

m

0;41 or 41

Red

m

0;42 or 42

Green

m

0;43 or 43

Brown

m

0;44 or 44

Blue

m

0;45 or 45

Purple

m

0;46 or 46

Cyan

m

0;47 or 47

Light Gray

m

1;40

Dark Gray

m

1;41

Light Red

m

1;42

Light Green

m

1;43

Yellow

m

1;44

Light Blue

m

1;45

Light Purple

m

1;46

Light Cyan

m

1;47

White

m

48;5;N

色拡張①。調整量N(0~255)でカラーコードを指定

m

48;2;R;G;B

色拡張②。調整量R/G/B(各0~255)をRGBカラーコードで指定


カーソル操作

ここからがANSIエスケープシークエンスの真骨頂であるカーソル操作の主な機能です。

なお一覧に載せた機能は全てのターミナルに対応している訳ではないので、一部使えないことにご留意ください。

操作・機能

A

y(移動量)

現在のカーソルからy行上へ

B

y(移動量)

現在のカーソルからy行下へ

C

x(移動量)

現在のカーソルからx文字右へ

D

x(移動量)

現在のカーソルからx文字左へ

E

y(移動量)

現在のカーソルからy行下の先頭へ

F

y(移動量)

現在のカーソルからy行上の先頭へ

G

x(移動量)

現在の行のx文字目の絶対位置へ

H

y;x(移動量)

y行目のx文字目の絶対位置へ

f

y;x(移動量)

Hと同じ

s

無し

現在のカーソルの位置を記憶

u

無し

記憶していたカーソルの位置に戻る

だいたいxterm系のターミナルでは、ほとんど全ての機能に対応してそうですが、他は端末エミュレータでどうかは不確かです。

その都度確認頂くとして、様々なOSの端末で動くシェルアプリを作成したい場合、あまりマイナーな処理(上記でいうと
sなど)は使用しないほうが良いかも知れません。

とりあえず、現在の端末に次のスクリプトを入力してみましょう。

            
            $ echo -e -n "\e[7B\e[20C\e[1;37m\e[41m---- HELLO, MY FIRST SHELL APP! ----\n\e[4A\e[m"
        
まずが端末の上から何行か下でこれを実行して下さい。)

合同会社タコスキングダム|蛸壺の技術ブログ

まず最初はカーソルを7行下げて、20文字目右に移動し、文字色を白、背景色を赤に変えております。

そこから、「---- HELLO, MY FIRST SHELL APP! ----」を端末に出力させています。

さらに文字列の出力後、カーソル位置から4行上げて、設定をデフォルトに戻して処理が完了しています。

なお、ANSIエスケープシークエンスを使わなくても、
tputコマンドというユーティリティコマンドを使うことでターミナルで簡単なカーソル操作を行うことも可能です。

ただし、画面上への描画位置をより柔軟に制御したい場合、tputで開発を進めていくと、
tput 〇〇;tput △△;tput □□;...のように冗長なスクリプトに肥大化していく傾向(「tput地獄」)にあります。

tputで組んでいたシェルアプリを途中でエスケープシークエンスにリファクタリングするのは非常に骨が折れますので、どうせなら最初からエスケープシークエンスでカーソル操作を作成してしたほうが良いと思います。


スクロール操作

画面のスクロールという操作もエスケープシークエンスで実現できます。

操作・機能

S

y(移動量)

現在のカーソルからy行下へ

T

y(移動量)

現在のカーソルからy行上へ

スクロールとカーソル移動は一見同じことをやっているようで、違う操作です。

挙動の違いが気になる方は実際にやってみてください。


出力の削除

出力した文字を消去する操作もエスケープシークエンスで可能です。

操作・機能

J

0 or 無し

現在のカーソルより後方の文字を消去

J

1

現在のカーソルより前方の文字を消去

J

2

画面全体をクリア

K

0 or 無し

現在のカーソルより後方の行を消去

K

1

現在のカーソルより前方の行を消去

K

2

行全体を全て


まとめ

今回はシェルアプリ開発で必須のANSIエスケープシークエンスの基礎をまとめてみました。

このGUIアプリケーション全盛期に、CUIアプリ開発の話などかなりマイナーな話かも知れませんが、やっていくとかなり楽しい世界が広がっていると思います。

どんなシェルアプリを作りたいか追々考えていくとして、まずがエスケープシークエンスの操作に慣れることから始められてはいかがでしょうか。

参考サイト

ANSI エスケープシーケンス: 色とカーソル操作

ANSIエスケープシーケンス チートシート

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。