Bash: как фильтровать вывод tee в реальном времени для команды ssh?

Моя цель — составить журнал команд, используемых в моих сеансах ssh, с отметками времени.

Тройник работает в режиме реального времени, пока выходные данные не фильтруются. Когда я завершаю -F test.log, следующая команда добавляет вывод в реальном времени:

#!/bin/bash
ssh "$@" | tee -a test.log

Однако, когда я пытаюсь изменить вывод tee методами, предложенными в этот вопрос, вывод больше не в реальном времени. Например:

#!/bin/bash
ssh "$@" | tee >(grep -e '.*\@.*\:.*\$.*' --color=never >> test.log)

Как ни странно, если я заменю команду «yes» вместо команды ssh, вывод будет правильно отфильтрован в реальном времени.

Обработка в реальном времени важна, потому что мой сценарий должен добавлять текущую метку времени к каждой строке и удалять как можно больше вывода. Вот мой скрипт на данный момент:

#!/bin/bash
logfile=~/test.log
desc="sshlog ${@}"
tab="\t"
format_line() {
    while IFS= read -r line; do
        echo "$(date +"%Y-%m-%d %H:%M:%S %z")${tab}${desc}${tab}${line}"
    done
}
echo "[START]" | format_line >> $logfile
ssh "$@" | tee >(grep -e '.*\@.*\:.*\$.*' --color=never | format_line >> $logfile)
echo "[END]" | format_line >> $logfile

Как я могу это исправить, и почему команда ssh работает с tee иначе, чем команда yes?


person Oleg    schedule 23.06.2014    source источник


Ответы (1)


Проблема, скорее всего, заключается в том, что grep буферизует свой вывод, выбирая большие куски ввода, фильтруя их и выводя результат, поэтому он гладко обрабатывает вывод yes (поскольку yes быстро генерирует много ввода для фильтрации и вывода), тогда как ваша команда ssh, вероятно, не так быстро генерирует столько вывода.

Многие версии grep предлагают механизм для настройки этой буферизации. Поскольку вы работаете в Linux, вы, вероятно, используете GNU Grep, который предлагает для этой цели флаг --line-buffered (см. Options.html">раздел "Другие параметры" Руководства по GNU Grep), чтобы выходные данные буферизировались только по одной строке за раз:

ssh "$@" | tee >(grep -e '.*\@.*\:.*\$.*' --color=never --line-buffered >> test.log)
person ruakh    schedule 23.06.2014
comment
если бы вы использовали awk вместо grep, вы бы использовали fflush(); . Этот вопрос связан с: stackoverflow.com/questions/21098382/ - person phyatt; 15.12.2016
comment
@ruakh Я проверил вашу команду перенаправления вывода tee. Вообще говоря: «какая-то команда» | tee ›( 'некоторая фильтрация' › 'вывод' ) Это работает, используя /bin/bash, это работает. Но я получил синтаксические ошибки, используя его в /bin/sh, например: Синтаксическая ошибка: (неожиданно. Любое предложение? Спасибо за вашу поддержку :) - person GrayFox; 20.12.2019
comment
@GrayFox: замена процесса (функция >(...)) здесь на самом деле находится в вопросе - я просто включил его здесь, чтобы показать параметр --line-buffered в контексте, поэтому я думаю, что в этом вопросе неуместно спрашивать, как приблизить замену процесса в оболочке, которая его не поддерживает. К счастью, вам не нужно спрашивать: этот вопрос уже ссылается на stackoverflow.com/q/12205250/978917, который имеет несколько ответов, показывающих подходы, основанные на не-подстановке процессов. - person ruakh; 20.12.2019