ANSI エスケープコードで自分だけのコマンドラインを構築する(2016)

2026/02/28 12:48

ANSI エスケープコードで自分だけのコマンドラインを構築する(2016)

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

記事は、ANSI エスケープコードが端末の外観とカーソル位置を細かく制御できる方法を説明し、色付き出力、進捗バー、および対話型コマンドラインインターフェースなどの機能を可能にします。

主な機能

  • 基本色(前景:
    30–37
    、背景:
    40–47
    )と明るいバリエーション(
    ;1
  • \u001b[38;5;<ID>m
    /
    \u001b[48;5;<ID>m
    (ID 0–255)による 256 色サポート
  • カーソル移動:
    \u001b[{n}A/B/C/D
    (上/下/右/左)、次行・前行、列設定、位置設定などのコマンド
  • 消去:画面
    \u001b[{n}J
    、行
    \u001b[{n}K
    n=0,1,2

実用例

  • \u001b[1000D
    を使って前回の出力を上書きする単純な進捗バー
  • 空白行を印刷し、
    \u001b[{count}A
    で上に移動させることで複数の同時進行バーを実現
  • tty.setraw
    sys.stdin.read(1)
    を用いた最小限の Python REPL。表示ロジックは行頭へ移動し、消去して現在入力を印刷し、カーソル位置を再設定する。Enter、Backspace(127)、矢印キー(27 91 68/67)も処理
  • ANSI コードを挿入することで構文ハイライトを追加可能。例:末尾空白は赤背景で強調

著者と背景
Haoyi は Scala ツールの Ammonite REPL と Mill Build Tool で知られ、コマンドラインユーティリティ開発経験を共有

結論
これらのエスケープシーケンスは、REPL、テキストエディタ、進捗バー、または任意の軽量対話型ツールなど、重いライブラリに頼らずに豊富な端末 UI を構築する基盤です。開発者が独自 CLI アプリケーションで実験・拡張できるよう奨励します。

本文

ターミナルに出力がスクロールして表示されることに慣れた皆さん、実際にはそれだけではありません。
プログラムはテキストの色を変えたり、カーソルを上下左右へ移動させたり、画面の一部を消去したりして、後で再描画するために使うこともできます。これが Git のダイナミックな進捗表示や Vim・Bash がスクロールせずに既存テキストを編集できる仕組みの根幹です。

Readline、JLine、Python Prompt Toolkit など、多言語で利用可能なライブラリもありますが、自分で実装することも十分可能です。この記事では、任意のコマンドラインプログラムからターミナルを制御する基本と、Python の例を通じてターミナルが提供するすべての特殊機能を直接利用する方法を紹介します。

著者について:Haoyi はソフトウェアエンジニアで、Ammonite REPL や Mill Build Tool など多くのオープンソース Scala ツールの作者です。この記事が気に入ったら、Haoyi の書籍 Hands‑on Scala Programming もぜひご覧ください。


ANSI エスケープコード

Unix ターミナルと対話するほとんどのプログラムは、ANSI エスケープコードを通じて行われます。これらはプログラムがターミナルに指示を送るために出力できる特殊なコードです。さまざまな端末でサポートされるコードのセットは異なるため、すべてのコードの意味を網羅した「権威ある」リストを見つけるのは難しいですが、Wikipedia などには妥当な一覧があります。

ANSI エスケープコードを利用するプログラムを書くことは可能であり、Ubuntu や OS‑X のような一般的な Unix システムでは動作します(Windows はここでは扱いません)。この記事では ANSI エスケープコードの種類と、それらを使ってインタラクティブなコマンドラインを最初から構築する方法を解説します。

リッチテキスト

    • 8 色
    • 16 色
    • 256 色
  • 背景色

  • 装飾

カーソル移動

  • 進捗表示
  • ASCII プログレスバー

コマンドラインの構築

  • ユーザー入力
  • 基本的なコマンドライン
  • カーソル移動
  • 削除
  • 完全性?

コマンドラインのカスタマイズ

結論


リッチテキスト

最も基本的な ANSI エスケープコードは、テキストを描画する際に使われるものです。これらは色や背景色、その他装飾を付けて出力しますが、特別な動作は行いません。出力された文字列はターミナルの下部に配置されスクロールしますが、デフォルトの黒/白ではなくカラーで表示されます。

テキストに色を付ける最も基本的な方法です。ANSI の色コードは次のようになります:

赤:    \u001b[31m
リセット:  \u001b[0m

\u001b
はほとんどの ANSI エスケープを開始する特殊文字です。Java、Python、JavaScript など多くの言語でこの表記が使えます。

例(Python 2):

print u"\u001b[31mHelloWorld"

Python 3 では先頭の

u
を省略できます。
出力後は必ず色をリセットしてください:

print u"\u001b[31mHelloWorld\u001b[0m"

8 色

基本端末には 8 色があります。

コード
\u001b[30m
\u001b[31m
\u001b[32m
\u001b[33m
\u001b[34m
マゼンタ\u001b[35m
シアン\u001b[36m
\u001b[37m
リセット\u001b[0m

各色の文字を 1 文字ずつ表示する例:

print u"\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m"
print u"\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m"

16 色

太字(明るい)色は

;1
を付けて表現します。

コード
明るい黒\u001b[30;1m
明るい赤\u001b[31;1m
明るい緑\u001b[32;1m
明るい黄\u001b[33;1m
明るい青\u001b[34;1m
明るいマゼンタ\u001b[35;1m
明るいシアン\u001b[36;1m
明るい白\u001b[37;1m
リセット\u001b[0m

256 色

16 色を超えると、いくつかの端末は 256 色セットをサポートします:

\u001b[38;5;<ID>m

例(Python):

import sys
for i in range(0, 16):
    for j in range(0, 16):
        code = str(i * 16 + j)
        sys.stdout.write(u"\u001b[38;5;" + code + "m " + code.ljust(4))
    print u"\u001b[0m"

背景色

背景色は前景色のコードを反映したものです。

コード
\u001b[40m
\u001b[41m
\u001b[42m
\u001b[43m
\u001b[44m
マゼンタ\u001b[45m
シアン\u001b[46m
\u001b[47m

明るいバージョンは

;1
を付け、前景色の明度に影響します。

print u"\u001b[40m A \u001b[41m B \u001b[42m C \u001b[43m D \u001b[0m"

256 色背景は

48;5;<ID>
を使用します。

装飾

その他の装飾コード:

装飾コード
太字\u001b[1m
下線\u001b[4m
逆転\u001b[7m

例:

print u"\u001b[1m BOLD \u001b[0m\u001b[4m Underline \u001b[0m\u001b[7m Reversed \u001b[0m"

カーソル移動

ANSI エスケープコードはカーソルを自由に移動させたり、画面の一部を消去したりできます。基本的な移動コマンド:

移動コード
上へ\u001b[{n}A
下へ\u001b[{n}B
右へ\u001b[{n}C
左へ\u001b[{n}D

進捗表示

単純なパーセンテージ表示例:

import time, sys
def loading():
    print "Loading..."
    for i in range(0, 100):
        time.sleep(0.1)
        sys.stdout.write(u"\u001b[1000D" + str(i+1) + "%")
        sys.stdout.flush()
    print

loading()

\u001b[1000D
はカーソルを画面左端に移動させ、古いパーセンテージを上書きします。

ASCII プログレスバー

import time, sys
def loading():
    print "Loading..."
    for i in range(0, 100):
        time.sleep(0.1)
        width = (i+1) // 4
        bar = "[" + "#" * width + " " * (25 - width) + "]"
        sys.stdout.write(u"\u001b[1000D" + bar)
        sys.stdout.flush()
    print

loading()

コマンドラインの構築

コマンドラインは単に ANSI コードでターミナルと対話するプログラムです。以下は Python で最小限実装した例です。

import sys, tty

def syntax_highlight(inp):
    stripped = inp.rstrip()
    return stripped + u"\u001b[41m" + " " * (len(inp) - len(stripped)) + u"\u001b[0m"

def command_line():
    tty.setraw(sys.stdin)
    while True:                # 各行ごとにループ
        input_str = ""
        index = 0
        while True:            # 各文字ごとにループ
            char = ord(sys.stdin.read(1))

            if char == 3:          # CTRL‑C
                return
            elif 32 <= char <= 126:
                input_str = input_str[:index] + chr(char) + input_str[index:]
                index += 1
            elif char in {10,13}:   # Enter
                sys.stdout.write(u"\u001b[1000D")
                print "\nechoing... ", input_str
                input_str = ""
                index = 0
            elif char == 27:        # エスケープシーケンス(矢印キー)
                next1, next2 = ord(sys.stdin.read(1)), ord(sys.stdin.read(1))
                if next1 == 91:
                    if next2 == 68:          # 左
                        index = max(0, index-1)
                    elif next2 == 67:        # 右
                        index = min(len(input_str), index+1)
            elif char == 127:          # Backspace
                if index > 0:
                    input_str = input_str[:index-1] + input_str[index:]
                    index -= 1

            # 現在の行を再描画
            sys.stdout.write(u"\u001b[1000D")   # 行頭へ移動
            sys.stdout.write(u"\u001b[0K")      # カーソル以降を消去
            sys.stdout.write(syntax_highlight(input_str))
            sys.stdout.write(u"\u001b[1000D")   # 再度行頭へ
            if index > 0:
                sys.stdout.write(u"\u001b[" + str(index) + "C")
            sys.stdout.flush()

command_line()

上記コードのポイント

  1. index
    を保持し、現在カーソル位置を追跡。
  2. 可視文字・Enter・矢印キー(左/右)・Backspace の入力を処理。
  3. \u001b[0K
    でカーソル以降を消去してから再描画。
  4. シンプルな構文ハイライト関数で末尾空白を背景色付きで表示。

コマンドラインのカスタマイズ

syntax_highlight
を好きなものに差し替えれば、Pygments など本格的な言語ハイライトも実装可能です。キーシーケンスを解釈して適切な ANSI コードを出力すれば、ドロップダウンメニューや Shift+矢印での選択・ブロックインデントなども追加できます。


結論

ANSI エスケープコードだけで最小限のコマンドラインを実装できることは、基本制御命令を理解すれば驚くほど簡単です。そこから構文ハイライト、多行編集、カスタムプロンプト、さらにはターミナルゲームまで、入力シーケンスとカーソル操作・テキスト操作のマッピングで実装できます。

リッチなターミナルインタラクション(進捗バー、編集可能なプロンプト、カスタムエディタ)が必要になったら、これらの ANSI コードを知っておくことで、自分だけの機能を構築する土台が手に入ります。

同じ日のほかのニュース

一覧に戻る →

2026/03/03 7:32

メタ社のスマートグラスの裏側にいる作業員は、全てを見渡すことができます。

## Japanese Translation: > Metaの新しい「Meta Ray‑Ban」メガネは、仕事・旅行・リアルタイム翻訳・プライバシー制御を一つのAIアシスタントとして位置付けられています。EssilorLuxotticaと共同で製造され、スウェーデンで販売される予定で、2023‑24年に200万台から2025年秋には700万台へと売上が急増する見込みです。このデバイスはサーバー側で処理を行う必要があり、ローカルでの対話は不可能です。アプリは電話にインターネット接続がなくても、常にMetaサーバーにアクセスします。 > Metaのプライバシーポリシーでは、ユーザーが明示的にオプトインしない限り、音声・テキスト・画像・動画を自動的に取得することが許可されています。すべてのコンテンツはAIによって自動または手動でレビューされる可能性があり、オプトアウトの選択肢はありません。プライバシー専門家は、ユーザーがしばしばメガネのカメラがAIアシスタントに話しかけた際に録画していることを認識していない点を指摘し、透明性の欠如を強調しています。 > データ注釈作業はサブコントラクター(例:ナイロビのSama)に委託されており、従業員は極めてプライベートな資料(例:トイレ訪問、セックスシーン、銀行カード情報など)をレビューすることがあります。匿名化は不完全であり、照明が悪い場合には顔が見えてしまう可能性があります。Metaの利用規約では保存場所や詳細な取り扱いについて具体的に示されておらず、ヨーロッパの幹部はGDPR準拠がサーバー所在地よりもデータ保護基準に依存していると指摘し、法的責任はMeta Irelandに帰属すると述べています。 > スウェーデンのプライバシー保護機関はまだ製品をレビューしていないため、ユーザーが自分のデータがAIモデルのトレーニングや広告ターゲティングにどのように使用されるかを十分に理解できていないという懸念があります。MetaはクラウドベースのAI処理を維持しつつメガネの販売を継続する計画であり、これがGDPR監視の強化につながり、企業や消費者がウェアラブルAIデバイスにおけるより明確なオプトインデータポリシーを要求する動きを促す可能性があります。

2026/03/03 6:09

Macintoshへようこそ(お帰りなさい)。

## Japanese Translation: --- ## Summary 著者は、最近の macOS リリース―特に不安定な「macOS Tahoe」―が継続的なバグと頻繁な UI 変更に悩まされており、システムの安定性やユーザー体験を侵食していると主張しています。主要な問題点は次の通りです: - **Time‑Machine バックアップ** は古いスナップショットが削除されない限り失敗します。 - **Spotlight** のタグインデックスは不完全な結果しか返さず、インデックスを再構築したり Finder を再起動しても部分的にしか解決しません。 - **Finder** は Spotlight クエリ中や検索結果の更新時にハングします。また、外部ファイルが作成された後にフォルダ内容を更新できず(*Go To Folder* やパスオートコンプリートといった回避策も限定的で、しばしば Finder の再起動が必要になります)。 - **AirPods Pro** は約 1 秒後に音声の不具合を起こし、ファームウェアや OS アップグレードでは問題は解決されません。 - **全画面ウィンドウ** は Cmd + Tab で切り替えるとフォーカスが失われ、キーボードショートカットが機能せず、ウィンドウをクリックするまで Safari のビデオコントロールに影響します。 これらの問題は複数の macOS リリースおよび Mac モデル(著者自身の M1 Max 2021 を含む)で継続しており、Apple 自身のコンポーネントに起因することを示しています。著者は、アイコン変更やダークパターン UI の微調整といった Apple の迅速な美観修正が長期的信頼性を損ねる可能性があると警告しています。将来のアップデートでバグが対処されることは期待できるものの、安定性よりも視覚的洗練を優先することへの懸念があります。 **Rosetta 2 の段階的廃止** は ARM64 Linux コンテナサポートに依存している開発者にとってさらに悪影響を及ぼし、アプリケーションの互換性を脅かす恐れがあります。総じて、著者は Apple に対し、短期的な美観更新よりもソフトウェア安定性、謙虚さ、および長期的利用価値に再集中するよう訴えています

2026/03/03 5:30

ブリティッシュコロンビア州、時刻変更を廃止し一年中サマータイムを採用

## Japanese Translation: ### 改訂要約 ブリティッシュコロンビア州は、2026年11月1日付で「太平洋時間(Pacific Time)」と呼ばれる夏時間を永久に採用し、それ以降の時刻変更をすべて終了します。デービッド・エビー首相は月曜日にこの決定を発表し、3月8日(最後の春先進調整)が最終的な移行となると述べました。この動きは、2019年の公衆意見調査で回答者の93%が健康・安全上の理由から永久夏時間を支持したことに続くものです。エビー氏は子供やペットの睡眠不足、二度の時刻変更による車両事故増加を強調しました。歴史的に、BC州は1918年以降に時刻を切り替えてきました(法務長官ニキ・シャルマ氏が指摘)。州政府は最終変更前に住民に8か月の調整期間を設け、カリフォルニア州、オレゴン州、ワシントン州といった米国隣接州にも同様の法案採択を促しています。東部BC地域(例:デイソンクリーク)はすでに年間を通じて山岳標準時を観測しているため除外されます。新制度下では、バンクーバーの永久夏時間で最も早い日の出は6月5:06 AM、最も遅い日は12月9:08 AMです。夕暮れは12月5:14 PMから6月9:22 PMまで変動します。この変更は生活品質の向上、事故リスクの低減、およびイエローナイフ州と同じ年間を通じて夏時間を採用することでBC州を調和させることを目的としています。

ANSI エスケープコードで自分だけのコマンドラインを構築する(2016) | そっか~ニュース