Программа Kill после вывода данной строки из сценария оболочки

15

Фон:

Я пишу тестовый сценарий для части программного обеспечения вычислительной биологии. Программное обеспечение, которое я тестирую, может работать несколько дней или даже недель, поэтому оно имеет встроенную функцию восстановления в случае сбоя системы или сбоя питания.

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

Это программное обеспечение печатает строку для каждого раздела анализа, который он завершает.

Вопрос:

Мне было интересно, если есть хороший / элегантный способ (в сценарии оболочки), чтобы захватить вывод из программы, а затем убить программу, когда данная строка / количество строк выводится программой?

Павел
источник
1
Почему вам нужно остановить программу в определенное время? Из-за буферизации вывода вы можете в конечном итоге убить программу после того, как она выведет текст, который вы проверяете.
Stardt
@stardt Я хотел остановить программу в определенное время, чтобы результаты теста были более контролируемыми и воспроизводимыми. Я нашел способ обойти это сейчас. Я убью программу только один раз вручную, затем протестирую только код восстановления. Все попытки восстановления начнутся с одной и той же точки. Я проверяю, как он восстанавливается, а не как он все-таки падает :)
Paul

Ответы:

7

Подобный скрипт-обертка является стандартным подходом. Сценарий запускает программу в фоновом режиме, а затем зацикливается, проверяя файл журнала каждую минуту на наличие какой-либо строки. Если строка найдена, фоновая программа уничтожается и скрипт завершается.

command="prog -foo -whatever"
log="prog.log"
match="this is the what i want to match"

$command > "$log" 2>&1 &
pid=$!

while sleep 60
do
    if fgrep --quiet "$match" "$log"
    then
        kill $pid
        exit 0
    fi
done
Кайл Джонс
источник
14

Если ваша программа завершит работу в SIGPIPE (что является действием по умолчанию), этого должно быть достаточно для передачи вывода в ридер, который выйдет при чтении этой строки.

Так что это может быть так же просто, как

$ program | sed -e '/Suitable text from the line/q'

Если вы хотите подавить вывод по умолчанию, используйте

$ program | sed -n -e '/Suitable text from the line/q'

Аналогично, если кто-то хочет остановиться после определенного количества строк, можно использовать голову вместо sed, например

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

Точное время, в которое происходит уничтожение , зависит от буферизационного поведения терминала, как предполагает stardt в комментариях.

dmckee --- котенок экс-модератора
источник
-1. Здесь есть серьезный недостаток. Программа завершится только тогда, когда (если) она попытается записать в (прерванный) канал после sedзавершения. OP говорит: «Это программное обеспечение печатает строку для каждого раздела анализа, который оно завершает». Это может означать, что программа завершит один дополнительный раздел! Доказательство концепции: { echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'. Смотрите этот ответ . Возможный обходной путь: ( program & ) | sed -e '/Suitable text from the line/q'; killall program. Сделайте так, чтобы ваш ответ знал о недостатке, и я отзову свое понижение.
Камиль Мачоровски
Хм ... действительно. И проблема буферизации делает ее ненадежной даже с вашим улучшением (хотя, конечно, это влияет на каждое решение, которое я вижу здесь). Мне нравится использовать сигнальную инфраструктуру, когда это возможно, но в какой-то момент она начинает терять свою элегантность. Возможно, лучше просто отказаться от всего этого.
dmckee --- котенок экс-модератора
7

В качестве альтернативы ответу dmckee можно также использовать grepкоманду с командой -moption (см., Например, эту страницу руководства):

compbio | grep -m 1 "Text to match"

останавливаться, когда найдена 1 строка, соответствующая тексту, или

compbio | grep -v -m 10 "Text to match"

ждать 10 строк, которые не соответствуют заданному тексту.

stardt
источник
3

Вы можете использовать expect(1)для просмотра стандартного вывода программы, а затем выполнить предопределенное действие для некоторых шаблонов.

#!/usr/bin/env expect

spawn your-program -foo -bar 
expect "I want this text" { close }

Или однострочник для встраивания в другой скрипт:

expect -c "spawn your-program -foo -bar; expect \"I want this text\" { close }"

Обратите внимание, что expectкоманда поставляется не со всеми ОС по умолчанию. Возможно, вам придется установить его.

Jamesits
источник
Это хорошее решение. Я рекомендую упомянуть, set timeout -1чтобы установить неопределенный тайм-аут, в противном случае он все закроется при expectтайм-ауте по умолчанию 10 секунд.
pepper_chico
1

Вы можете использовать выражение "while":

Вам нужно направить вывод вашего программного обеспечения (или его журналов), а затем, для каждой новой строки, выполнить условный тест, а затем запустить kill -KILL. Например (я тестировал с / var / log / messages в качестве файла журнала):

tail -f /var/log/messages | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Или с программным обеспечением напрямую:

./biosoftware | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Вам нужно заменить путь журнала / имя приложения, строку для сопоставления и PID для уничтожения (вы также можете использовать killall).

Удачи с вашим программным обеспечением,

Hugo,

фисташка
источник