問題
SSH 経由で大量の情報を出力するコマンドを実行します。たとえば、何百万回も実行されるループ内にデバッグ情報を愚かにも追加したり、単にcat /dev/urandom
面白半分に実行したりします。
端末には情報が溢れています。
コマンドをできるだけ早く終了してプログラムを修正したい。何が印刷されるかは気にしない。問題は、Ctrl+ CASAP(上記の例ではコマンドを実行した直後に押した)を押すことだが、必要のない情報も全部印刷するのにまだ時間がかかる。
私が試したこと
Ctrl+ をC強く押そうとしたので、ターミナルがようやく追いついたときに面白い結果になりました。
OUTPUT HERE^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
^C^C
^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
Ctrl私はまた、 +について読みましたS。どうやら端末に「出力を停止してください、追いつく必要があります」と伝えるために使用されますしかし、どうやら何も起こらないようです。
その他詳細
実行するプログラムがそのようになる可能性があることを覚えていなくても、どのような状況でも自分自身を救出できるように、実行するコマンドを変更しないようにしたいと思います。
私の SSH クライアントは、CYGWIN_NT-6.1-WOW64 luna 1.7.30(0.272/5/3) 2014-05-23 10:36 i686 Cygwin
ターミナル タイプが に設定された MinTTY の Cygwin ( ) 上で実行されますxterm-256color
。
SSH サーバーは Debian ( Linux burza 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 i686 i686 GNU/Linux
) 上で実行されます。
答え1
私は通常、キーを使用する代わりless
に を介してそれを強制終了できるように、出力を実行します。less
q
$ cmd | less
例
$ cat /dev/urandom | less
q+を押すとEnter終了し、通常のターミナルに戻り、きれいな状態になります。
なぜそうなるのでしょうか?
発生している問題は、ディスプレイの出力でキューに入れられているバッファ (STDOUT 用) があることです。これらのバッファは非常に早くいっぱいになるため、停止するのに十分な速さで中断することができません。
この効果を無効/制限するには、STDOUT バッファリングを無効にすることができます。これにより、 を使用すると応答性が少し向上しますstdbuf
が、希望どおりの結果を得るにはこれらの設定を試してみる必要があるでしょう。STDOUT のバッファリングを解除するには、次のコマンドを使用します。
$ stdbuf -o0 <cmd>
stdbuf
利用可能なオプションの詳細については、man ページを参照してください。
If MODE is 'L' the corresponding stream will be line buffered. This
option is invalid with standard input.
If MODE is '0' the corresponding stream will be unbuffered.
Otherwise MODE is a number which may be followed by one of the
following: KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so
on for G, T, P, E, Z, Y. In this case the corresponding stream will be
fully buffered with the buffer size set to MODE
bytes.
バッファリングの仕組みに関する背景情報については、次のタイトルの Pixel Beat の記事をご覧になることを強くお勧めします。標準ストリームでのバッファリング素敵な写真も載っています。
参考文献
答え2
出力の一部はバッファリングされます。リモート エンドにCtrl+を送信するCと、実行中のプログラムが中断されます。プログラムが終了し、シェルはプロンプトを再度表示するための文字を送信します。プロンプトが表示される前に、バッファリングされて既に送信中のすべてのデータが画面に表示されます。
あなたが求めているのは、プログラムを停止し、転送中のデータを何らかの方法で消去することです。すでに転送中なので、それは起こり得ません。
このデータが表示されないようにする唯一の方法は、自分の端末を終了してリモートに再接続することですが、これはバッファリングされたデータが表示されるのを待つよりもはるかに手間がかかるでしょう。
答え3
バッファリングにはいくつかのレベルがあります。Ctrl+を押すとC、プログラムが端末にデータを送信しなくなります。これは、端末エミュレータがまだ表示していないデータには影響しません。
非常に高速にデータを表示する場合、端末は追いつけず、遅延します。ここで起きているのは、テキストの表示がこれらの乱数を生成するよりもはるかにコストがかかるということです。はい、ビットマップ フォントを使用した場合でも、暗号品質の乱数を生成することは、それに比べれば非常に安価です。(自分のマシンで試したところ、X プロセスが CPU を飽和させ、xterm
数 % を消費し、cat
(乱数生成を考慮して) 1 % に達するのがやっとでした。これはビットマップ フォントを使用した場合です。)
これを今すぐ停止したい場合は、ターミナル エミュレータを終了します。これを実行したくない場合は、少なくともウィンドウを最小化します。インテリジェントなターミナル エミュレータ (xterm など) はウィンドウをマップしないため、X CPU 時間が節約され、不要なメッセージの表示がより早く終了します。X サーバーは優先度が高いため、xterm がバックグラウンドでデータを処理している間、マシンの応答性に大きな違いが生じます。
これらすべてがリモート シェルで実行されている場合、 によって生成されたデータはcat
まず SSH 接続を通過する必要があるため、遅延はさらに悪化します。Ctrl+を押すCと、SSH 接続を通過する必要があります。これは、いくらか優先度が高くなります (帯域外で送信されます) が、それでも、より多くの出力が蓄積される間に時間がかかります。SSH 接続を閉じる以外に、転送中のデータを抑制する方法はありません (これは、 を押してEnterから を押すことで実行できます~.
)。
答え4
私も同じ問題を抱えていましたが、ここでの回答に満足できなかったので、さらに深く調べました。他の人がすでに述べているように、コマンドは ssh が処理できるよりも速くデータを出力しているため、データ バッファとバッファを停止することはできません。
これを修正するには、コマンド出力を SSH セッションが実行できる最大速度に制限してバッファリングを回避します。これを行うコマンドはすでに存在します。
セットアップでは、まずセッションの最大レートを確認します。
# Get transfer <TIME> of a large file (>10MB preferable)
/usr/bin/time -f "%e" cat <FILENAME>
# Get file <SIZE> in bytes
stat --printf="%s\n" <FILENAME>
# Calculate <RATE>
echo "<SIZE> / <TIME>" | bc
最後に、実際のコマンドをそれに応じて調整します。
<YOUR_COMMAND> | pv -qL <RATE>
例:
/usr/bin/time -f "%e" cat large_reference_file.txt
31.26
stat --printf="%s\n" cat large_reference_file.txt
17302734
echo "17302734 / 31.26" | bc
553510
# Throttle my command to 553510B/s
cat some_other_file.txt | pv -qL 553510
接続速度が時々低下する場合は、RATE を少し下げたほうがよいかもしれません。接続速度が低下すると、Ctrl + C が反応しなくなるという問題が再発します。
オプションのスロットルされた cat エイリアス:
# bash
alias tcat='tcat(){ cat $@ | pv -qL 400k ; }; tcat'
# tcsh
alias tcat 'cat \!* | pv -qL 400k'
# usage: tcat <FILENAME>
今では ctrl-c は期待どおりに動作し、バッファリングされるものがほとんどないため、出力は直ちに終了します。