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