"наблюдать" за выводом команды до тех пор, пока не будет обнаружена определенная строка, и затем выйти
Я ищу способ программно наблюдать за выводом команды, пока определенная строка не наблюдается, а затем выйти. Это очень похоже на этот вопрос, но вместо хвоста файла я хочу "хвостить" команду.
Что-то вроде:
смотреть -n1 my_cmd | grep -m 1 "Строка, которую я ищу"
(Но это не работает для меня.)
ОБНОВЛЕНИЕ: Мне нужно уточнить, что my_cmd не выводит текст непрерывно, но его нужно повторно вызывать до тех пор, пока не будет найдена строка (вот почему я подумал о команде 'watch'). В этом отношении my_cmd похож на многие другие команды unix, такие как: ps, ls, lsof, last и т. Д.
6 ответов
Используйте цикл:
until my_cmd | grep -m 1 "String Im Looking For"; do : ; done
Вместо :
, ты можешь использовать sleep 1
(или 0,2) для облегчения работы процессора.
Цикл выполняется до тех пор, пока grep не найдет строку в выводе команды. -m 1
означает "достаточно одного совпадения", т.е. grep прекращает поиск после того, как находит первое совпадение.
Вы также можете использовать grep -q
которая также завершается после нахождения первого совпадения, но без печати совпадающей строки.
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
!
отменяет код выхода командного конвейераgrep -m 1
выходит, когда строка найденаwatch -e
возвращает, если произошла какая-либо ошибка
Но это может быть улучшено, чтобы фактически отобразить эту согласованную линию, которая пока отброшена.
Для тех, у кого есть программа, которая постоянно записывает в stdout, все, что вам нужно сделать, это передать ее в grep с опцией 'single match'. Как только grep найдет соответствующую строку, он выйдет, что закроет стандартный вывод процесса, который передается в grep. Это событие должно естественным образом вызывать корректное завершение программы до тех пор, пока процесс не запишется снова.
Что произойдет, так это то, что процесс получит SIGPIPE, когда попытается записать в закрытый стандартный вывод после выхода grep. Вот пример с ping, который в противном случае работал бы бесконечно:
$ ping usersuper.ru | grep -m 1 "icmp_seq"
Эта команда будет соответствовать первому успешному "понгу", а затем выйти в следующий раз ping
пытается писать на стандартный вывод
Тем не мение,
Не всегда гарантируется, что процесс снова запишет в stdout и, следовательно, может не вызывать SIGPIPE для поднятия (например, это может произойти при подключении файла журнала). Лучшее решение, которое мне удалось найти для этого сценария, включает запись в файл; пожалуйста, прокомментируйте, если вы думаете, что можете улучшить:
$ { tail -f log_file & echo $! > pid; } | { grep -m1 "find_me" && kill -9 $(cat pid) && rm pid; }
Разбивая это:
tail -f log_file & echo $! > pid
- привязывает файл, прикрепляет процесс к фону и сохраняет PID ($!
) в файл. Вместо этого я попытался экспортировать PID в переменную, но, похоже, между этим моментом и тем, когда PID снова используется, возникает условие гонки.{ ... ;}
- сгруппировать эти команды вместе, чтобы мы могли направить вывод в grep, сохраняя текущий контекст (помогает при сохранении и повторном использовании переменных, но не смог заставить эту часть работать)|
- труба с левой стороны к правой сторонеgrep -m1 "find_me"
- найти целевую строку&& kill -9 $(cat pid)
- сила убить (SIGKILL)tail
процесс послеgrep
выходит, как только находит соответствующую строку&& rm pid
- удалите файл, который мы создали
Чтобы просмотреть вывод без его изменения и с тайм-аутом, можно использовать приложение micro Python «waitforoutput».
pip install waitforoutput
waitforoutput 'String Im Looking For' --command 'watch my_cmd' --timeout 10
В официальном README есть более подробное объяснение поведения: https://pypi.org/project/waitforoutput/ .
Добавить результат ваших программных вызовов в файл. затем tail -f
этот файл. Таким образом, это должно работать... Я надеюсь.
Когда вы возобновите вызов этой программы, вам придется стереть файл или добавить к нему немного тарабарщины, чтобы он не совпадал с тем, что вы искали.
my_cmd | tail +1f | sed '/String Im Looking For/q'
Если tail
не поддерживает +1f
синтаксис, попробуйте tail -f -n +1
, (The -n +1
говорит, что нужно начинать с самого начала; tail -f
по умолчанию начинается с последних 10 строк вывода.)