
Linux で cal を実行すると、現在の月の出力で現在の日が反転表示されます。その出力を hexdump -c に送信すると、興味深い結果が得られます。
0000000 N o v e m b e r 2 0 1 6
0000010 \n S u M o T u
0000020 W e T h F r S a \n
0000030 1 2 _ \b _ \b 3
0000040 4 5 \n 6 7
0000050 8 9 1 0 1 1 1 2 \n
0000060 1 3 1 4 1 5 1 6 1 7 1
0000070 8 1 9 \n 2 0 2 1 2 2
0000080 2 3 2 4 2 5 2 6 \n 2 7
0000090 2 8 2 9 3 0
00000a0 \n
00000b0 \n
00000bc
ご覧のとおり、今日強調表示されている '3' の前に、_\b _\b という目に見えないシーケンスが印刷されています。_ はアンダースコア (ASCII 16 進数では 5F)、\b は Ctrl-H または ASCII 16 進数では 08 です。これは何でしょうか。わかりにくいターミナル コードがたくさんあることは知っていますが、\e[7m のようなもっと標準的なコードが使用されると予想します。さらに奇妙なのは、次のコマンドのいずれかのような標準の printf 関数を使用して同じ文字を印刷しても、cal と同じ動作を再現できないことです。
/usr/bin/printf "1 2 _\b _\b3 4 5\n"
/usr/bin/printf "1 2 _^H _^H3 4 5\n"
ここで、^H は Ctrl-V Ctrl-H を押すことで作成されます。しかし、どちらも cal と同じ反転ビデオ出力を生成しません。私も、これを行うために小さな C プログラムを書いてみました。また、echo -e でも試しました。興味深いのは、端末でビデオが反転しないのに、less -R からの出力をパイプすると、色が黄色に変わり、下線が引かれることです。他の端末では、下線だけが引かれるように試しました。まるで重ね打ちのように見えますが、_ 以外の文字を使用すると機能しないので、_\b は単一のコード シーケンスであると考えられます。では、その文字のビデオはどのようにして反転されるのでしょうか。
これについて何か知見はありますか?
man ページには、cal の出力は元の Unix cal コマンドとビット単位で互換性のあるバージョンになるはずだと書かれています。したがって、これは古いコードだとしか思えません。
答え1
まるで過剰攻撃のようだ
まさにその通りです。80 列のコンソールにタブストップが 11 個あるのはなぜですか?、Unix 端末に関しては、機械式タイプライターの動作を思い浮かべると分かりやすいでしょう。この場合、_
文字の前のシーケンス BS (バックスペース文字) は、その文字に下線を引くことを示すために使用される慣例です。一部の端末では、テキストに下線を引くときにこのシーケンスが使われていたからです。別の制御シーケンスは、_
文字の後の BS です。もちろん、オリジナルの端末では、どの文字がどの文字に重なっても問題ありませんでした。現代のビデオ端末では、最後に書き込まれた文字が「勝ち」、前のデータが消去されます。したがって、_
BS <キャラクター>順番が優先されます。
このプログラムであるFreeBSDncal
には、ハイライト表示に関して 2 つの動作モードがあります。
so
出力が端末の場合、termcap データベースで現在の端末タイプのおよびシーケンスを検索しse
、強調表示されたテキストの両側にそれらを出力します。(実際にこれを行うコードにはバグがあり、スタック上のバッファがスコープ外になり、その内容が後で使用されることに関係していますが、誰も気付いていないようです。)- 出力が端末でない場合は、強調表示する各文字の前に BS シーケンスを付けたテキストを出力します
_
。
BS シーケンスを端末に送ることでこれを再現することはできません_
。ただし、(もちろん) 端末が、このように下線を引く端末の 1 つである場合は除きます。これは端末エミュレーターには当てはまりませんし、ここで使用している端末や端末エミュレーターにもほぼ間違いなく当てはまりません。
ただし、フィルターこの規則を使用するテキストを プログラムは、この規則とその他のいくつかのタイプライターのような規則を認識し、termcap データベースで検索して、端末の実際の制御シーケンスに変換します。を通じてコマンドul
の出力をフィルタリングすることもできます。printf
ul
他の端末で試してみたところ、下線が引かれるだけでした。
ncal
皮肉なことに、プログラムを通しての非端末モード出力をフィルタリングすることは、端末制御シーケンス自体を書き込むul
よりもわずかに優れていますncal
。一方、ncal
は端末の目立つモードでは、ul
端末の実際の下線BS シーケンスを変換するときに、強調モード (ある場合) を使用します_
。termcap マニュアルで説明されているように、強調モードは端末に適したものであれば何でもかまいません (太字、反転表示、色など)。必ずしも下線が引かれている必要はありません。端末の 1 つでは、明らかに下線と色の変更の組み合わせになっています。
さらに、ul
下線の開始/終了シーケンスを持たないが、下線最後の文字シーケンスを持つ端末にも対応します。皮肉なことに、ul
端末が本当に_
各文字の後にBS を付けて下線を引くもの。ncal
対応できません。
もちろん、のバッファ処理バグもul
ありません。☺ncal
出力を にパイプすると
less -R
、色が黄色に変わり、下線が引かれます。
お気づきのとおり、less
プログラムは BS シーケンスを理解し_
、プログラムと同じように処理しますul
。完全に同じではありません。 ul
複数の BS 文字を含むシーケンスを処理でき_
、太字の同様のシーケンスも処理できます。 less
できません。次の 2 つを比較してください。
/usr/bin/printf "1 2 ______\b\b\b\b\b\b\b 3 _\b4. \b\b\b45 6\n" | ul
/usr/bin/printf "1 2 ______\b\b\b\b\b\b\b 3 _\b4. \b\b\b45 6\n" | 以下
古き良き時代に戻る
残念なことに、これらはまだ「古き良き時代」です。現在ではほとんど使用されていないと騙されないでください。
マニュアルには記載されていないが、のソースコードでは、ul
テレタイプモデル37の制御シーケンス処理を実装しようとしていることが指摘されている。なぜなら、「それがnroff
出力される」からだ。端末が色、太字、斜体などの派手な機能を獲得してからずっと後に書かれた、オリジナルのUnixプログラムのGNU代替品はnroff
、次のようなものを生成することができる。ECMA-48色、太字、斜体の制御シーケンス。実際にそうする通常の場合。
nroff
およびその GNU 代替品は、端末に表示するためのマニュアル ページの書式設定に使用されます。悲しいことに、皮肉なことに、作成されてから約 10 年後、人々は GNU ツールを妨害し、1976 年の「新しい」ECMA-48 制御シーケンスではなく、1968 年の古い Teletype Model 37 シーケンスを生成するようにしました (sic!)。彼らは、デフォルトの動作を変更するオプションを指定してman
呼び出しgroff
、追加の ditroff 出力を強制する文書化されていないファイルを追加しました。
端末でマニュアル ページを読むたびに、マニュアル システムが実行され、groff
マニュアルのソース テキストが、古い Teletype Model 37 制御シーケンスを使用して出力文字ストリームに変換され、端末の制御シーケンスに変換されますless
。more
参考文献
答え2
Ctrl-H
はバックスペースで、カーソルを 1 ステップ左に移動します。古き良き時代には、ハード コピー (「紙」) 端末で何かに下線を引くには、アンダースコア、バックスペース、およびその他の文字を送信していました。これは、 の出力で現在の日付を強調表示するために使用されていましたcal
。
私のcal
プログラムは、実行時にkonsole
このシーケンスを出力しません。実行してscript -c cal
結果のファイルを調べると、cal プログラムがエスケープ シーケンスを使用して逆モード ビデオに切り替えていることtypescript
がわかります。<esc>[7m