"наблюдать" за выводом команды до тех пор, пока не будет обнаружена определенная строка, и затем выйти

Я ищу способ программно наблюдать за выводом команды, пока определенная строка не наблюдается, а затем выйти. Это очень похоже на этот вопрос, но вместо хвоста файла я хочу "хвостить" команду.

Что-то вроде:

смотреть -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; }

Разбивая это:

  1. tail -f log_file & echo $! > pid - привязывает файл, прикрепляет процесс к фону и сохраняет PID ($!) в файл. Вместо этого я попытался экспортировать PID в переменную, но, похоже, между этим моментом и тем, когда PID снова используется, возникает условие гонки.
  2. { ... ;} - сгруппировать эти команды вместе, чтобы мы могли направить вывод в grep, сохраняя текущий контекст (помогает при сохранении и повторном использовании переменных, но не смог заставить эту часть работать)
  3. | - труба с левой стороны к правой стороне
  4. grep -m1 "find_me" - найти целевую строку
  5. && kill -9 $(cat pid) - сила убить (SIGKILL) tail процесс после grep выходит, как только находит соответствующую строку
  6. && 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 строк вывода.)

Другие вопросы по тегам