Как добавить строку в начало вывода программы, не дожидаясь завершения всей строки?

Как добавить строку в начало вывода программы, не дожидаясь завершения всей строки?

У меня есть скрипт, который запускает команду на удаленном сервере с помощью SSH. Я хочу добавить строку Remote:к каждой строке вывода, но не хочу, чтобы каждая строка задерживалась, пока не станет доступна вся строка. Вот вывод моей команды:

$ myproject-db-push имя_моей_базы_данных
Экспорт из базы данных... Готово
Архивация данных... Готово
Загрузка архива на удаленный сервер... Готово
Запуск скрипта установки на удаленном компьютере
Удаленно: Распаковка архива во временный каталог... Готово
Удаленно: Использование базы данных: my_database_name
Удалённо: Удаление коллекций:
Удалённо: - my_collection_foo
Удалённо: - my_collection_bar
Удаленно: Импорт новых данных... Готово

В этом случае я использую sedвот так:

echo "$INSTALLCMD" | ssh -T "deploy@$SERVER" | sed -u "s/^/Remote: /"

Проблема в том, как я уже объяснил, что нетчастичныйлинии печатаются на экране. Если я удаляю часть | sed, она работает как и ожидалось. Сначала это написано:

Импорт новых данных...

И через несколько секунд строка завершается:

Импорт новых данных... Готово

Я предполагаю, sedчто он может работать только построчно. Я пробовал установить его в режим без буферизации, но он все равно ждет целые строки. Есть ли другой способ сделать это?

решение1

Это немного сложно, потому что все эти утилиты ( sed, awk, grep) буферизуются построчно. Это означает, что они печатают вывод только после завершения строки (появления новой строки). Они не могут читать ввод посимвольно.

Поэтому для тестирования я создал небольшую последовательность, имитирующую ваше поведение:

{ 
  echo -n "first task: "
  sleep 2
  echo "done"
  echo -n "second task: "
  sleep 2
  echo "done"
}

Как и в вашем вопросе, он печатает first task:и через 2 секунды done. Попробуйте сами, скопировав его в свой терминал.

Решение:

Добавьте следующее после вашей команды:

IFS=
command | { x=1; while IFS= read -d'' -s -N 1 char; do
  [ $x ] && printf "Remote: "
  printf "$char"
  unset x
  [ "$char" == "
" ] && x=1
done; }

Объяснение:

readВстроенная функция может bashсчитывать вводимые символы посимвольно. Часть read -d'' -s -N 1 charотключает разделитель -d'', активирует тихий режим -sи считывает только 1 символ за раз -N 1в переменную $char. Затем команда проверяет, $xсуществует ли переменная. Если да, мы находимся на новой строке и печатаем «префикс». Затем печатаем символ. Unset $x. Затем последний оператор проверяет, является ли символ новой строкой. Если это новая строка, устанавливается $xзначение 1и в следующем цикле будет напечатан «префикс».

Все это можно проверить, если объединить две последовательности:

{ 
  echo -n "first task: "
  sleep 2
  echo "done"
  echo -n "second task: "
  sleep 2
  echo "done"
} | { x=1; while IFS= read -d'' -s -N 1 char; do
  [ $x ] && printf "Remote: "
  printf "$char"
  unset x
  [ "$char" == "
" ] && x=1
done; }

Связанный контент