web-dev-qa-db-ja.com

端末のバックスペースの動作

これは、バックスペース(_\b_)文字の動作に関するものです。次のCプログラムがあります。

_int main() {
    printf("Hello\b\b");
    sleep(5);
    printf("h\n");
    return 0;
}
_

私の端末の出力は

_Helho
_

カーソルが次の行の最初の位置に移動します。

まず、全体が5秒間スリープした後にのみ印刷されるので、カーネルからターミナルへの出力はラインバッファリングされると推定されます。だから今、私の質問は:

  1. _\b\b_は(2番目の)lの位置まで2スペース戻るため、lhに置き換えられたのと同様に、oは_\n_に置き換えられました。なぜでしたか?
  2. printf("h\n");を削除すると、Helloが出力され、消去せずに2文字戻ります。私が他の答えから得たこれは、非破壊的なバックスペースのためです。この動作が入力と出力で異なるのはなぜですか?つまり、端末に何か(まったく同じプログラムでも)を入力してBackspaceを押すと、最後の文字は消去されますが、出力は消去されません。どうして?

私はbashを使用してxtermターミナルでUbuntuシステムを使用しています。

3
forumulator

まず、全体が5秒間スリープした後にのみ印刷されるので、カーネルからターミナルへの出力がラインバッファーであると推定されます。

いいえ、プログラムからカーネルへの出力はラインバッファリングされます。これは、stdioが端末である場合のstdoutのデフォルトの動作です。 stdoutの出力バッファリングをオフにするには、setbuf(stdout, NULL)呼び出しを追加します。 setbuf(3) を参照してください。

  1. \b\bは2つのスペース、lの位置まで戻るため、lhに置き換えられたのと同様に、o\nに置き換えられました。なぜでしたか?

改行文字はカーソルを移動する(そして画面をスクロールする)だけなので、端末のグリフの場所を占める目に見える文字としては印刷されません。グリフの代わりになると仮定すると、どのように見えますか?

  1. まったく同じプログラムに何かを入力してBackspaceキーを押すと、最後の文字は消去されますが、出力は消去されません。どうして?

入力したときに何が起こるかは、端末がどのモードにあるかによって異なります。おおよそ、端末自体が基本的な行編集を提供する(バックスペースを処理する)通常の「クック」モードにすることができます。または、「raw」モードでは、すべてのキープレスがアプリケーションに送られ、それらをどのように処理し、それに応じて何を出力するかはアプリケーション次第です。クックドモードは通常、「ローカルエコー」と一緒に使用され、入力された文字をターミナル(ユーザーに対してローカル)が出力します。 rawモードでは、アプリケーションは通常、入力された文字をエコーし​​、表示内容を完全に制御します。

たとえば、ターミナルモードに関するディスカッションのためのこの質問: 「未加工」と「調理済み」のデバイスドライバーの違いは何ですか?

あなたが実行した場合cat、ターミナルはクックドモード(デフォルト)になり、行編集を処理します。たとえば打つ xBackspaceCtrl-D 空の入力を読み取るだけでcatが発生し、入力の終了を通知します。これはstraceで確認できます。しかし、代わりにインタラクティブなBashシェルを実行すると、バックスペースを単独で処理し、ユーザーが期待することを実行するのに適切と見なされるものを出力します。つまり、1文字をワイプします。


上記のシーケンスを入力した後のstrace -etrace=read,write -obash.trace bashの出力の一部を次に示します xBackspaceCtrl-D

read(0, "x", 1)                         = 1
write(2, "x", 1)                        = 1
read(0, "\177", 1)                      = 1
write(2, "\10\33[K", 4)                 = 4
read(0, "\4", 1)                        = 1

まず、Bash readsとwrites xを使用して、ターミナルに出力します。次に、バックスペース(8進数の文字コード0177または10進数の127)を読み取り、バックスペース文字(8進数の010、10進数の8)を出力します。(*))カーソルを後ろに移動しおよびは、行の終わりをクリアするための 制御シーケンス を出力します<ESC>[K。最後の\4Ctrl-Dで、Bashがプログラムを終了するために使用します。

(*入力では、Ctrl-Hは10進文字コード8になります。バックスペースは、端末の設定方法に応じて、ここと同じか127です。)

比較すると、catを使用した同じ実験では、0バイトの単一の読み取り、つまり「ファイルの終わり」条件のみが示されています。ファイルの終わりとは、接続されたパイプまたはソケットが閉じられているか、実際のファイルの終わりであるか、またはクックモードの端末からCtrl-Dが受信されていることを意味します。

read(0, "", 131072)                     = 0

特に、catxもバックスペースもCtrl-Dの実際のコードも認識しません。これらは端末によって処理されます。カーネルの仮想端末ドライバーかもしれません。シリアル接続などを介した実際の物理端末;または、同じマシン上で、またはSSH接続のリモートエンドで実行されているxtermのようなターミナルエミュレータ。ユーザースペースソフトウェアには関係ありません。

3
ilkkachu

まず、これについて知りたい場合は、

あなたが尋ねる、

…何かを入力して…Backspaceキーを押すと、最後の文字は消去されますが、出力は消去されません。どうして?

これがちょっとした豆知識です:Unixのごく初期(1970年代、Linuxが存在する以前)、バックスペース1入力文字を消去しなかったため、ユーザーはそれを嫌っていました。 「beast」と入力し、Backspaceキーを3回押しても、邪魔なbe|astがあなたを見つめています(|はカーソルを表します)。 stと入力した後も(ずっとbestと言うつもりだったため)、画面にはbest|tと表示され、混乱を招きました。

多くのユーザーがタイピングの習慣を採用しました BackspaceSpaceBackspace スペースを使用して悪い文字を置換/破壊するために、消去したい文字ごとに1回。つまり、手動で消去します。最終的に(1979年または1980年代初頭)、開発者たちはこれを容認し、これを自動化しました。

バックスペースを押すと、カーネルのtty行の制御により、前の文字が(単純な場合は)Ctrl-H、スペース、次に別のCtrl-Hで印刷されます。
出典: テキスト入力中にバックスペースを入力したときにUnixが消去する方法

「Ctrl-H」はバックスペースの制御コードです。

状況によっては、このオプションをオフにしてstty -echoeechoe =“ echo erase”、-「しないでください」を意味します)。
____
1実際、ごく初期の段階では、バックスペースはバックスペースではありませんでしたが、それは別の話です。

コード(\b\n etc)テキストではなくカーソルを移動します。

太字のフォントやテレタイプ、ゴルフボールプリンターなどで取り消し線などの驚くべき効果を得るためにプリンターでカーソルを操作しなければならなかったときの動作は、「古き良き時代」に由来することがわかると思います。

\bは、挿入ポイントを戻し、上書きするだけです。デジタル画面では前のコンテンツが削除されますが、古いプリンターではオーバーレイ文字が表示されます。

\nはカーソルを新しい行に移動しますが、テキストを古い行に残します。これは、カーソルを行の先頭に戻し、プリンターに行を上にスクロールするように指示するCRLFでした。

CR、LFおよびCRLFコード は、古いデバイスを操作してこれらの新しい効果を得る必要性に再び関連付けられています。

.....そして、印刷されたページから文字を削除する方法がありませんでした。印刷するために投稿する直前にそれを取得することが期待されていました。

[〜#〜]編集[〜#〜]

ポイント2について。あなたが指示しているので、入力と出力は異なることをします。

\bは、削除ではなく挿入をオフにした左矢印と同等です。

\nは「Enter」キーストロークではなく、下矢印(LF)およびHOME(CR)と同等です。

3
bu5hman