21

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

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

смотреть -n1 my_cmd | grep -m 1 "Строка, которую я ищу"

(Но это не работает для меня.)

ОБНОВЛЕНИЕ: мне нужно уточнить, что «my_cmd» не выводит текст непрерывно, но его нужно повторно вызывать до тех пор, пока не будет найдена строка (именно поэтому я подумал о команде «watch»). В этом отношении my_cmd похож на многие другие команды Unix, такие как: ps, ls, lsof, last и т.д.

5 ответов5

30

Используйте цикл:

until my_cmd | grep -m 1 "String Im Looking For"; do : ; done

Вместо : вы можете использовать sleep 1 (или 0.2) для облегчения работы процессора.

Цикл выполняется до тех пор, пока grep не найдет строку в выводе команды. -m 1 означает "достаточно одного совпадения", т.е. grep прекращает поиск после того, как находит первое совпадение.

8
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
  • ! отменяет код выхода командного конвейера
  • grep -m 1 выходит, когда строка найдена
  • watch -e возвращает, если произошла какая-либо ошибка

Но это может быть улучшено, чтобы фактически отобразить ту согласованную линию, которая пока отброшена.

5

Для тех, у кого есть программа, которая постоянно записывает в stdout, все, что вам нужно сделать, это передать ее в grep с опцией 'single match'. Как только grep найдет соответствующую строку, он выйдет, что закроет стандартный вывод процесса, который передается в grep. Это событие должно естественным образом вызывать корректное завершение программы до тех пор, пока процесс не запишется снова.

Что произойдет, так это то, что процесс получит SIGPIPE, когда попытается записать в закрытый стандартный вывод после выхода из grep. Вот пример с ping, который в противном случае работал бы бесконечно:

$ ping superuser.com | grep -m 1 "icmp_seq"

Эта команда будет соответствовать первому успешному pong, а затем завершится при следующей ping выполнить запись в stdout.


Тем не мение,

Не всегда гарантируется, что процесс снова запишет в 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 - удалить созданный нами файл
0
my_cmd | tail +1f | sed '/String Im Looking For/q'

Если tail не поддерживает синтаксис +1f , попробуйте tail -f -n +1 . (-n +1 говорит, что он должен начинаться с начала; tail -f по умолчанию начинается с последних 10 строк вывода.)

0

Добавить результат ваших программных вызовов в файл. Затем tail -f этого файла. Таким образом, это должно работать ... Я надеюсь.

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .