У меня есть скрипт, который запускает команду на удаленном сервере с помощью 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; }