小さなExpectスクリプトの作成中にスクリプトを実行した後、bash入力にいくつかの文字が自動的に表示されることがわかりました。以前は他のプログラムでこれが起こっているのを見たことがありますが、ここには再現可能なものがあります。
私の予想されるスクリプトは次のとおりです。
#!/usr/bin/expect
spawn ssh root@[lindex $argv 0]
expect "password:"
send "[lindex $argv 1]\r"
expect "~#"
結果は次のとおりです。
user@PC:~$ expect test.exp 192.168.0.2 root
spawn ssh [email protected]
[email protected]'s password:
^[[51;117Rroot@device:~# user@PC:~$ ;117R
-bash: syntax error near unexpected token `;'
user@PC:~$
出力の5行目に示すように、^[[51;117R
stdout()にはいくつかのランダムな文字があり、その一部はシェル入力行(;117R
)に漏れます。 Expectスクリプトを実行してEnterキーを押すと、bashは(;117R
)をbashに入力したかのように解釈しようとします。
私の質問はここで何が起こっているのか、それをやめる方法です。
答え1
これらはすべていいえ「任意の文字」。
% printf '\e[51;117R' | |コンソール復号 ECMA48 心肺蘇生術51; 117 %
リモートシステムのログインプロセス中に実行されるタスクは、デバイスステータスレポート制御シーケンスをその端末に送信し、その端末からカーソル位置レポートを要求することです。ターミナル(数ホップの距離にあり、ssh
DSR出力を通過して転送したターミナルexpect
)がそれを生成し、時間内に送信しています。
% printf '\x1b[6n''コンソールデコードECMA48; ^[[30;1R 心肺蘇生術30; 1 もし %
これらのレポートは、入力したのと同じ方法で端末からホスト(つまり、端末に直接接続されているシステム)に転送されます。ホストシステムで実行されているプログラムが単にカーソル位置レポートを入力していないことを知るための信頼できる方法はありません。もちろん、この時点では端末入力への読み取りと送信はありません。したがって、CPRはキューに追加され、完了時にシェルである端末から入力をexpect
読み取る次のプログラムによって読み取られるようになります。expect
あなたが見ているのは、シェルが入力と同じ制御シーケンスにどのように反応するかです。
これは、端末入力処理が実際に常に適切なステートマシンを備えた適切なECMA-48デコーダでなければならない理由の1つです。シェルのライン編集システムはそうではありません。 (ZLE、Readline、またはlibeditは実際には端末入力制御シーケンスを正しく処理しません。)パターンマッチングを使用してコンテンツをデコードしますが、これは正しい操作を実行しません。制御シーケンスの最初の4文字のみを無視する方法に注意してください。適切なECMA-48入力デコーダがデコードされます。みんな最後の文字まで、すべてのパラメータ文字を含む制御シーケンスはそれをCPRとして認識し、(希望的に)無駄な入力として破棄します。
まず心肺蘇生を要求するには、まずリモートシステムを確認し、ターミナルログイン時にどのプログラムが実行されているかを確認する必要があります。犯人はXtermかもしれません。resize
プログラム。 (このプログラムが端末でない場合はXtermを使用しないでください。TERM
環境変数を特定のxterm
型に誤って設定する可能性があるためです。)しかし、それはresize
唯一の可能性ではありません。
追加読書
- ジョナサンデボインポラード(2018)。 」
console-decode-ecma48
」。 スナックガイド。ソフトウェア。 - ジョナサンデボインポラード(2019)。 」
TERM
」。 スナックガイド。ソフトウェア。 - https://unix.stackexchange.com/a/444270/5132