Проблема
Я выполняю команду, которая выводит МНОГО информации через SSH. Например, я по глупости добавляю отладочную информацию в цикл, который выполняется миллион раз, или просто запускаю cat /dev/urandom
ради прикола.
Терминал переполнен информацией.
Я хочу завершить команду как можно скорее и исправить свою программу. Мне все равно, что она напечатает. Теперь, дело в том, что я нажимаю Ctrl+ Cкак можно скорее (в примере выше я нажал его сразу после запуска команды), новсе равно требуется время, чтобы распечатать всю информацию, которая мне даже не нужна.
Что я пробовал
Я пытался нажимать на 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 ( CYGWIN_NT-6.1-WOW64 luna 1.7.30(0.272/5/3) 2014-05-23 10:36 i686 Cygwin
) в MinTTY с типом терминала, установленным на 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
Подробная информация о доступных вам возможностях приведена на странице руководства :
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 нагружал процессор, забирая xterm
несколько % и cat
(что учитывается при генерации случайных чисел) едва достигая 1%. И это с растровым шрифтом.)
Если вы хотите, чтобы это прекратилось немедленно, закройте эмулятор терминала. Если вы не хотите этого делать, то хотя бы сверните окно; интеллектуальные эмуляторы терминала (например, xterm) не будут отображать окно, что экономит время X CPU, поэтому мусор будет отображаться быстрее. X-сервер имеет высокий приоритет, поэтому это сильно повлияет на скорость отклика вашего компьютера, пока xterm обрабатывает данные в фоновом режиме.
Когда все это происходит в удаленной оболочке, задержка становится еще больше, потому что данные, созданные с помощью, cat
сначала должны пройти через SSH-соединение. Ваше нажатие Ctrl+ Cтакже должно пройти через SSH-соединение; оно получает несколько более высокий приоритет (отправляется за пределы диапазона), но это все равно занимает некоторое время, в течение которого накапливается больше выходных данных. Нет способа подавить данные в пути, кроме как закрыть SSH-соединение (что можно сделать, нажав Enterthen ~.
).
решение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.
Дополнительный псевдоним для категоризированного пользователя:
# bash
alias tcat='tcat(){ cat $@ | pv -qL 400k ; }; tcat'
# tcsh
alias tcat 'cat \!* | pv -qL 400k'
# usage: tcat <FILENAME>
Теперь ctrl-c работает так, как и ожидалось, немедленно уничтожая вывод, поскольку буферизуется очень мало данных, если вообще буферизуется.