私は最近エスケープシーケンスを調べてきたし、それができることに驚きました。 X11ウィンドウの移動にもxterm
使用できます(試してみてくださいprintf '\e[3;0;0t'
)。うわー!
端末がどの機能をサポートしているかを調べる最も一般的な方法は、データベースを使用するようです。これは、ncurses
エスケープシーケンスに依存するアプリケーションの99.9%がそれを使用することです。
Ncursesは、コンソールでサポートされている機能を決定するために、terminfo
シェル環境変数のデータベースを読み取ります。シェルの環境変数を変更できます。これにより、ほとんどのアプリケーションがより少ない機能を使用したり、誤動作(実行または設定を試みた後)を開始したりできます。TERM
TERM
nano
vim
TERM=""
一部のエスケープコードによって、端末が何かを報告するようになることがわかりました。たとえば、端末にカーソル<ESC>[6n
位置を報告させるようにします。 ( printf '\e[6n'
)
- 同様の報告メカニズムを使用してコンソールにサポートされている機能を報告するようにしたいですか?
各コンソールは機能を値に結合するのではなく、独自の機能を宣伝することで、TERM
全体をより正確かつ信頼性の高いものにすることができます。なぜこれはあまりないのですか?
編集:以前に尋ねたことがありました...新しいエスケープシーケンスを作成し、konsoleとgnome-terminalをハックしてそれをサポートし、いくつかのスクリプトで使用したいと思います。
私が実行しているコンソールがこの機能をサポートしていることを確認するためにコンソールに問い合わせたいと思います。推奨されるアプローチは何ですか?
答え1
思ったほど簡単ではありません。 xterms(たとえば、VT100で始まるDEC VTxxx端末)には、さまざまな状況に関する多くのレポートがあります。特徴(引用するXTerm制御シーケンス)。最も一般的に有用なのは、端末の種類を知らせることです。
CSI Ps c Send Device Attributes (Primary DA).
すべての端末にこの種の応答があるわけではありません(Sunハードウェアコンソールではまったく)。
ただし、レポートよりも多くの機能があります(たとえば、端末が実際にUTF-8を解釈していることを確認するには:許可されるパスは次のようになります。)ロケール環境変数なので、他の制御シーケンス/応答を構築する必要はありません。
実際にはレポートに焦点を当てたいくつかのアプリケーションがあります(例:ウィム、ファンクションキーの実際の値、使用されている色の数を確認してください。DCS + p Pt ST
、またはカーソル形状を使用してDCS $ q Pt ST
)、一部の開発者は、機能を実装するよりも、与えられたレポート応答を返す方が簡単だと思うので、プロセスを信頼できません。さまざまなプログラムのソースコードを読んで、誰かが特定のバージョンのxtermのように見えるように応答をカスタマイズした興味深い機能を見つけることができます。
答え2
端末エミュレータのエスケープシーケンスを照会する方法は次のとおりです。
要約:非同期特性のため、アプリケーションはこれを処理するのに問題があります。 (ケーキの一部であるターミナルエミュレータを介していません。)
まず、簡略化のために、すべての端末エミュレータがこれらすべてのクエリに対する応答を送信することが保証されているとします。 (これを行うには、クエリに1回のエスケープシーケンスではない明確に定義された共通構造が必要ですが、そうではありません。)
シンプルなユーティリティ(「ls」など)とより複雑なフルスクリーンアプリケーション(「mc」や「vim」など)を心の中に設計して実装し、どの問題に直面しているかを見てみましょう。
Unixの標準機能は、前のコマンドの実行中に事前に次のコマンドを入力できることです(たとえば、「sleep 10」Enterを入力してから「mc」Enterを入力し、F5を押すと約10秒後に、 「mc」をクリックすると、コピーダイアログボックスが開きます。)人々はこの機能が好きかもしれませんが、少なくとも動作はアプリケーション全体で一貫している必要があります。 「私は、起動時にこのようなクエリエスケープシーケンスを使用してその機能が何であるかを判断します。今、mcは応答する前にF5エスケープシーケンスを受け取ります。これを無視するか(この場合、動作はアプリケーションの残りの部分と一致しません)いいえ)どこかに保存してクエリへの応答が届くまで待ってから、このF5を処理する必要があるかもしれません。実行可能ですが、実装にはかなりの努力が必要です(この標準なしですでに実装されているプロジェクトはもちろん、最初から始まるプロジェクトの場合でも必要な追加の作業が明らかであるため、多くのリファクタリングが必要です)。
何らかの理由で操作中に端末を照会する必要がある場合、同様の状況が発生します。その後、応答が到着する前に中間の「一般」文字を捨てることは決して許容できません。
シェルスクリプト自体がCや同様の言語で書かれたユーティリティプログラムではなく、ユーザーから(標準入力から)この応答や他の一般的な入力を読む必要があることを想像してみてください。どうやって行きたいですか?これらの応答を処理するコードの各「読み取り」に対して、終端を手動で改行または応答エスケープシーケンスの終わりに設定し、残りのエスケープシーケンスを見つけて削除しますか?ユーザー入力がまだある間に画面にエスケープシーケンスの応答が表示されないようにするにはどうすればよいですか?ユーザーデータを期待する後続の「正規」「読み取り」コマンドに対するエスケープシーケンスの応答を期待するときに受信する一般的な入力をどのように「供給」しますか?どうすればいいかわかりませんが、可能であっても我慢できないほど複雑で退屈でエラーが発生しやすいです。合理的に達成可能で安定して動作すると考えられる唯一のアプローチは、オートコンプリート文字(予期しない動作を引き起こす)を削除し、スクリプトの起動時にこれらの応答エスケープシーケンスのみを処理することです。
ループ内のシェルスクリプトで単純なユーティリティ(「ls」など)を使用すると、ターミナルエミュレータとアプリケーション間のラウンドトリップ時間が大幅に長くなる可能性があります。シングルコアシステムでは、2つのアプリケーション(ユーティリティとターミナルエミュレータ)間のコンテキスト切り替えが必要ですが、とにかく発生したfork()+ execve()+friendsと比較してそれほど大きな問題ではありません。こんな。マルチコアシステムではこれは必要ないようですが、詳細についてはわかりません。ただし、実際のネットワークトラフィックが関係する場合、コスト(遅延時間)が大幅に増加する可能性があります。
応答を読み取らずにアプリケーションが終了するまれな場合(たとえば、競合または終了)、次に入力を開始するコマンドに応答が表示されます。バイナリファイルを分類しました)。
今後のエスケープシーケンスを含む特定のクエリエスケープシーケンスを認識しない(または単に応答しないように選択する)いくつかのターミナルエミュレータがあるとしましょう。これが現状です。これは以前のすべてのポイントをはるかに困難にします。この場合、アプリケーションが停止する危険性がないため、タイムアウトが必要です。
回答を受けるにはどれくらい待つべきですか?ランダムなタイムアウトを補償する方法は?ネットワークの特性(ローカル端末エミュレータ、近隣の建物のSSH、世界の反対側のSSHなど)に基づいてこのタイムアウトを調整します(そしてどのように)?
SSH遅延などのために応答が時間内に到着しない場合はどうなりますか?アプリケーションはユーザーに表示されるパフォーマンス低下モードになりますか?
アプリケーションが放棄したよりも応答が遅い場合はどうなりますか?応答がまったく予期しない場所に到着しても、これらの応答のためにアプリケーションを準備する必要があるかもしれません。 (たとえば、シェルスクリプトでは最初にいくつかの状態を照会し、タイムアウト応答を待ちますが、後続の各「読み取り」はこの遅延応答で汚染されるように準備する必要があります。)
タイムアウトはラウンドトリップ時間を多く追加し、カーネルコンテキストの切り替えやネットワーク待ち時間よりもはるかに長くなる可能性があります。これらのコマンドをシェルスクリプトループに入れることは決して耐え難いことですが、インタラクティブアプリケーションの使いやすさに重大な悪影響を及ぼす可能性があります。
私が考えるために実行可能な代替案を提示することは、この答えの範囲外です。 TERM変数の設計には多くの制限がありますので、ここでは詳しく説明しません。クエリ機能(カーソル位置などの現在のプロパティではなく端末エミュレータに静的)の場合は、実際の動作を説明するTERMCAPの方向から始めます。ローカルファイルを指し、今のようにTERMと呼ぶこともできますが、sshのようなユーティリティは.Xauthorityと同様の方法で実際のコンテンツをリモートサイトに渡し、そのファイルにTERMを指す役割を果たします。まったく異なるアプローチは、ターミナルエミュレータとのメタ通信に4番目の標準ファイル記述子を使用することです。