プログラム出力が端末プロンプトを上書きするのを防ぎます。

プログラム出力が端末プロンプトを上書きするのを防ぎます。

端末で次のコマンドを実行するとします。

~$ echo 'sleep 2; echo "hello!"' | sh

その後、次の行を入力し始めます。 2秒後、私が書いている内容に「hello!\n」という単語が挿入されます。回避策があることを知っていますが(プロンプトを更新するには上に押してから下に押します)、記録がない他のシステムでは(Telnet経由でMUDを使用している場合など)不可能です。

stdinとstdoutを分離するncursesアプリケーションや端末エミュレータを知っている人はいますか?これはncursesで行うのはとても簡単なようです。賢いdup2を使うだけです。しかし、実装する前に、誰かが以前にやったことがあるかどうかを知りたいです。

主な問題に対する他の解決策も歓迎します。

答え1

これは聞こえるように変更するのは簡単ではありません。これは、端末「cooked」対「raw」モードと「echo」を有効にするかどうかに関係します。

ターミナルがベークモード(デフォルト)にあるとき、カーネルは入力として入力されたすべての項目を読み取り、プレーンテキスト即時エコー、削除処理、文字削除(単一文字および全文字削除)を含む基本行編集機能を使用して処理します。します。 ) は、それぞれ現在行の内容と異なる内容です。 Enterキーを押すと、実際には端末入力にテキスト行が表示されます。 Enterキーを押すまでのプロセスはすべてカーネル内で発生します。端末で実行されているプロセスがシングルバイトを受信できませんでした。したがって、フォアグラウンドアプリケーションは、ユーザーが何も入力しているかさえ知りません。 ttyで実行されているプロセスは、必要に応じてこのエコーを抑制できません。これは、エコーが不適切な時間(出力と混合するなど)に現れるからです。これらのプロセスは、入力が発生しているという事実さえ知らないからです。

エコーを表示しない、stty rawまたはtermiosを使用する代わりにターミナルをrawモードに設定することでこれを抑制できますが、カーネルの行編集機能が完全に失われます。つまり、キーを押して再起動できないというCtrl意味です。uエラー。さらに、カーネル調理処理に依存するプログラム(基本的にはreadlineやncursesを使用しないすべてのプログラム)を使用するのに多くの困難があります。なぜなら、そのようなプログラムでは完全に盲目的に入力することになるからです!ああ、さらに:端末を処理しないと、中断され保留中のジョブ制御ショートカットのカーネルブロック機能が失われます(デフォルトはそれぞれCtrl-cCtrl- z)。

答え2

echo出力を画面の上部に送信するために後ろからエスケープされるいくつかのANSIを含めることができます。

printf %b\\n 'sleep 2; printf "\0337\033[H\033[Khello!\0338"' |sh

可能でなければなりません。機能するには、基本的なANSI互換端末が必要ですが、まだそのような端末がない場合は、おそらくそうする必要があります。他の人は1980年代からこの方法を使用してきました。

それぞれの場合、先行は\033リテラルの8進エスケープです。<ESC>文字 - たとえば、キーボードの左上隅を押すことができます。残りのすべてのシーケンスは、入力時に端末でカーソルアドレッシングコマンドとして解釈されます。

彼らは次のことをします:

  • 7
    • 後で復元できるようにカーソルの状態を保存します。
  • [H
    • カーソルをホームに移動 - 画面の最初の行の最初の列に移動します。
  • [K
    • 現在行のテキストを消去します。
  • 8
    • 最後に保存されたカーソル状態を復元します。

その結果、バックグラウンドプロセスは、カーソルを画面の左上に配置し、行を消去して次を書き込みます。こんにちは!をクリックして、カーソルを見つけた場所に戻ります。より複雑な組み合わせが可能で、より強力なソリューションを開発するために使用できますが、これは私が得たものです。

答え3

私が知っている唯一の解決策はを押すことです^R。入力したテキストを復元します。完璧ではありませんが、backspaceしばらくこだわって再起動するよりも優れています。

答え4

Telnet経由でゲームをプレイする場合のユースケースです。私は入力のために別のターミナルを使用しました。

次のように入力端子を作成します。

xterm -e bash -c "cat > '$(readlink -f /dev/stdin)'"

関連情報