"Спостерігайте" за результатами команди, поки не спостерігається певна рядок, а потім вийти


29

Я шукаю спосіб програмно спостерігати за результатами команди, поки не спостерігається певна рядок, а потім виходить. Це дуже схоже на це запитання, але замість того, щоб накреслити файл, я хочу команду "хвіст".

Щось на зразок:

дивитися -n1 my_cmd | grep -m 1 "String Im Looking"

(Але це не працює для мене.)

ОНОВЛЕННЯ: Мені потрібно уточнити, що "my_cmd" не виводить текст постійно, але його потрібно повторно викликати, поки не буде знайдено рядок (саме тому я подумав про команду "watch"). У цьому відношенні 'my_cmd' є як і багато інших команд unix, таких як: ps, ls, lsof, last тощо.


Я міг би подумати, що можна tail -fвивести програму так само добре, як і файл ... Я помиляюся?
Джоаніс

@Joanis. Ви маєте рацію, але в моєму випадку "my_cmd" не дає постійно виводити результат і його потрібно неодноразово викликати (подібно до більшості команд: ps, ls, lsof тощо)
gdw2

Відповіді:


41

Використовуйте цикл:

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

Замість цього :ви можете використовувати sleep 1(або 0,2) для полегшення процесора.

Цикл працює, поки grep не знайде рядок у висновку команди. -m 1означає "одного матчу достатньо", тобто grep припиняє пошук після того, як знайде першу відповідність.

Ви також можете використовувати, grep -qяка також закривається після пошуку першого збігу, але без друку відповідного рядка.


пояснення цієї команди було б вдячно.
Марк Ш

@MarkW: Оновлено.
choroba

хтось ще згадав, grep -qщо є іншим варіантом. grep закривається після знаходження рядка.
Нд

зауважте, що ця команда буде неодноразово виконувати відповідну команду, що може бути чи не бажаним.
adrien

1
@A__: Бажано, як зазначено в ОП у розділі "Оновлення".
choroba

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

Але це можна вдосконалити, щоб фактично відобразити ту відповідну лінію, яку покинутий поки що.


Дякую за детальне пояснення, але це не працює для мене. У моїй watchкоманді (CentOS) немає -eпрапора (що насправді не має значення). Що ще важливіше, проте, коли рядок знайдено, годинник продовжує працювати і не виходить. Здається, що при grep -mвиході він лише виводить вбивства my_cmd, але ні watch.
gdw2

Ні, не має значення! Прапор "-e" призначений для виходу з годинника, коли команда має код помилки, відмінний від 0. Оскільки її теперішній годинник вже продовжується на вашій платформі. У всякому разі, добре знати, що на моїй установці Ubuntu 11.10 все добре. У мене також іноді виникають проблеми з Mac OSX щодо дуже застарілих інструментів командного рядка, і я поки використовую порти mac, щоб отримати більш сучасне програмне забезпечення.
математика

Це зупиняється, якщо шаблон знайдений, але він не показує жодного результату, поки це не відбудеться
Марк

Ви можете взяти teeна роботу для цього, але це вводить оманливий новий рядок, я не знаю, як зараз обійти:watch -n1 -e "! date | tee /dev/tty | grep --color -m 1 \"17\""
математика

Так, для мене це не вийшло. watchприскіпливо перестає дивитись, коли рядок знайдено, але вона фактично не виходить, поки не натиснеш клавішу. Дуже близько.
mlissner

8

Для тих, хто має програму, яка постійно пише в stdout, все, що вам потрібно зробити, - це передати її для вибору з опцією "єдиний матч". Як тільки grep знайде відповідний рядок, він вийде, що закриває stdout в процесі, який переносять на grep. Ця подія повинна, природно, спричинити виграшну програму, поки процес знову пише .

Що станеться, процес отримає SIGPIPE, коли він намагається записати у закритий stdout після виходу 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 рядків виводу.)


Будь ласка, дивіться моє оновлення до питання.
gdw2

0

Додайте результат ваших програмних дзвінків до файлу. Потім tail -fцей файл. Таким чином воно має працювати ... сподіваюся.

Після перезапуску виклику цієї програми вам доведеться стерти файл або додати до нього якусь безглуздість, щоб вона знову не відповідала тому, що ви шукали.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.