シェル内で制御文字 (^C、^D、^[、...) を異なる方法で表示する方法

シェル内で制御文字 (^C、^D、^[、...) を異なる方法で表示する方法

シェルで制御文字を入力すると、それらは「キャレット表記」と呼ばれるものを使用して表示されます。たとえば、エスケープは^[キャレット表記で のように記述されます。

私は bash シェルをカスタマイズして、見た目をかっこよくするのが好きです。たとえば、 と を色付きに変更しPS1ましPS2た。今度は、制御文字にも独自の外観を与えて、通常の文字と区別しやすくしたいと思っています。

$ # Here I type CTRL-C to abort the command.
$ blahblah^C
          ^^ I want these two characters to be displayed differently

シェルで制御文字を別の方法で強調表示する方法はありますか?

太字のフォントで表示したり、通常のテキストとは異なる色で表示したりすることは可能ですか?

使っていますバッシュbashシェルについてはここで説明しますが、多くの異なるシェルに適用できる解決策があるかもしれないので、質問にタグを付けませんでした。

注記制御文字の強調表示がどのレベルで行われるのか分かりません。最初はシェル自体で行われるものだと思っていましたが、今では読み込まれた行シェル内での制御文字を制御するバッシュ。 そのため、この質問には現在 のタグが付けられておりreadline、私はまだ回答を探しています。

答え1

を押すとCtrl+X、端末エミュレーターはバイト 0x18 を擬似端末ペアのマスター側に書き込みます。

次に何が起こるかは、tty ライン ディシプリン (マスター側 (エミュレータの制御下) とスレーブ側 (端末で実行されているアプリケーションが対話する側) の間にあるカーネル内のソフトウェア モジュール) がどのように構成されているかによって異なります。

それを設定するコマンドtty ライン規律というコマンドですstty

このような愚かなアプリケーションを実行する場合、cat標準入力が端末であるかどうかを認識せず、気にしないので、端末はデフォルトで正統なttyラインディシプリンが粗雑な行エディタ

それ以上の粗雑さを必要とするインタラクティブアプリケーション行エディタ通常、起動時に設定を変更し、終了時に復元します。現代のシェルでは、彼らの指示に従ってはそのようなアプリケーションの例です。これらのアプリケーションでは、独自のより高度な行エディタを実装しています。

通常、コマンド ラインを入力すると、シェルは tty ライン ディシプリンをそのモードに設定し、Enter キーを押して現在のコマンドを実行すると、シェルは通常の tty モード (プロンプトを発行する前に有効だったモード) を復元します。

コマンドを実行するとstty -a、現在使用されている設定が表示されます。愚かなアプリケーションicanonechoおよび設定が有効になっていることがわかりますechoctl

つまり、次のようになります。

  • icanon: 粗いラインエディターが有効になります。
  • echo: 入力した文字(端末エミュレータがマスター側に書き込む文字)は反響した戻ります(ターミナルエミュレータで読み取り可能になります)。
  • echoctl: ではなく反響したasis、制御文字は反響したとして^X

では、 と入力したとしますA B Backspace-aka-Ctrl+H/? C Ctrl+X Backspace Return

端末エミュレータは以下を送信します:AB\bC\x18\b\r回線制御はエコーback: AB\b \bC^X\b \b\b \b\r\n、スレーブ側 ( /dev/pts/x) からの入力を読み取るアプリケーションは を読み取りますAC\n

アプリケーションが認識するのは のみでありAC\n、 が押されたときのみ認識されるEnterため、そこでの出力を制御することはできません^X

気づくと思いますがエコー、最初の文字^H(^?一部の端末では設定を参照erase)\b \bは端末に送り返されました。これはカーソルを戻し、スペースで上書きし、再びカーソルを戻すというシーケンスであり、2 番目の文字はこれら 2 つの文字と文字を消去し^Hました。\b \b\b \b^X

( 0x18 ) 自体は、出力用におよび^Xに変換されていました。 と同様に、Backspace キーで削除したため、アプリケーションには届きませんでした。^XB

\r(別名^M)は、エコーの場合は\r\n( )、アプリケーションの場合は( ) に変換されました。^M^J\n^J

では、それらの選択肢は何でしょうかバカアプリケーション:

  • 無効にしますecho( stty -echo)。これにより、制御文字がエコーされる方法が実質的に変更され、何もエコーされなくなります。実際のところ、これは解決策ではありません。
  • を無効にします。これにより、制御文字( 、...およびラインエディタで使用される他のすべての文字をechoctl除く)がエコーされる方法が変更されます。^H^M反響したそのままです。つまり、たとえば、ESC 文字は\e( ^[/ 0x1b) バイト (端末によってエスケープ シーケンスの開始として認識される) として送信され、 (端末のビープ音を鳴らす BEL)^Gが送信されます\a...これはオプションではありません。
  • 粗雑なライン エディター ( stty -icanon) を無効にします。粗雑なアプリケーションの使い勝手が大幅に悪くなるため、このオプションは実際には使用できません。
  • カーネルコードを編集してttyラインディシプリンの動作を変更し、エコー制御文字の\e[7m^X\e[m代わりに送信します^X(ここでは、\e[7mほとんどの端末で反転表示が有効になります)。

選択肢としては、rlwrapこのようなラッパーを使用するというものがあります。これは、ダム アプリケーションに派手な行エディタを追加する汚いハックです。このラッパーは、実質的に、端末デバイスからの単純な s を、readline 行エディタへの呼び出しに置き換えようとしますread()(これにより、tty 行規則のモードが変更されます)。

さらに進んで、次のような解決策を試すこともできます。これです^Xこれは、GNU screen の機能に依存して、端末からのすべての入力を zsh の行エディタ (s を反転表示で強調表示する) に渡します:exec

独自のラインエディタを実装しているアプリケーションの場合、どのように実装するかはアプリケーション側で決定します。エコー完了です。bashそのためには、制御文字のエコー方法をカスタマイズするサポートがない readline を使用します。

についてはzsh、以下を参照してください。

info --index-search='highlighting, special characters' zsh

zshデフォルトでは印刷できない文字が強調表示されます。たとえば、次のように強調表示をカスタマイズできます。

zle_highlight=(special:fg=white,bg=red)

特殊文字を赤地に白で強調表示します。

ただし、これらの文字のテキスト表現はカスタマイズできません。

^XUTF-8 ロケールでは、0x18 は、\u378\U7fffffff(割り当てられていない 2 つの Unicode コード ポイント) として<0378><7FFFFFFF>\u200b(実際には印刷できない Unicode 文字) としてレンダリングされます<200B>

\x80iso8859-1 ロケールでは^�... のように表示されます。

答え2

通常、.bashrc ファイルに次のコードがあります:

function get_exit_status()
{
        local code=$?
        if [ $code -ne 0 ]
        then
                printf $'\001\033[31m\002'"($code)"$'\001\033[0m\002'" "
        fi
}

そしてPS1でこの関数を呼び出します

PS1='\u@\h \w $(get_exit_status)'

これで、^Cを押すとプロンプトに表示されます

I@mycomputer ~ ^C
I@mycomputer ~ (130)

「0」以外のすべての終了ステータス コードがプロンプト表示されます。

関連情報