Подтвердить что ты не робот

Как запустить команду в цикле, пока не увижу какую-нибудь строку в stdout?

Я уверен, что есть какой-то тривиальный однострочный ключ с perl, ruby, bash, что бы это позволяло мне запускать команду в цикле, пока я не наблюдаю некоторую строку в stdout, а затем остановитесь. В идеале, я хотел бы также захватить stdout, но если он собирается консолировать, этого может быть достаточно.

В настоящее время конкретная окружающая среда - RedHat Linux, но для Mac тоже требуется такая же вещь. Так что-то, generic и * nixy было бы лучше. Не заботьтесь о Windows - предположительно, что * nixy будет работать под cygwin.

UPDATE: Обратите внимание, что "наблюдать за некоторой строкой" я имею в виду, что "stdout содержит некоторую строку", а не "stdout IS some string".

4b9b3361

Ответ 1

В Perl:

#!/usr/local/bin/perl -w

if (@ARGV != 2)
{
    print "Usage: watchit.pl <cmd> <str>\n";
    exit(1);
}

$cmd = $ARGV[0];
$str = $ARGV[1];

while (1)
{
    my $output = `$cmd`;
    print $output; # or dump to file if desired
    if ($output =~ /$str/)
    {
        exit(0);
    }
}

Пример:

[bash$] ./watchit.pl ls stop
watchit.pl
watchit.pl~
watchit.pl
watchit.pl~
... # from another terminal type "touch stop"
stop 
watchit.pl
watchit.pl~

Возможно, вы захотите добавить спать.

Ответ 2

Там было множество способов сделать это, первое, что пришло в голову, было:

OUTPUT=""; 
while [ `echo $OUTPUT | grep -c somestring` = 0 ]; do 
  OUTPUT=`$cmd`; 
done

Где $cmd - ваша команда для выполнения.

Для справки, здесь версия функции BASH, поэтому вы можете назвать это более легко, если это то, что вы хотите вызывать из интерактивной оболочки на регулярной основе:

function run_until () {
  OUTPUT="";
  while [ `echo $OUTPUT | grep -c $2` = 0 ]; do
    OUTPUT=`$1`;
    echo $OUTPUT;
  done
}

Отказ от ответственности: только слегка проверенные, возможно, потребуется выполнить дополнительное экранирование и т.д., если в ваших командах есть много аргументов или строка содержит специальные символы.

РЕДАКТИРОВАТЬ. Основываясь на отзывах от комментария Адама - если вам не нужен вывод по какой-либо причине (т.е. не хотите отображать вывод), вы можете использовать эту более короткую версию, с меньшим использованием backticks и, следовательно, меньшими накладными расходами:

OUTPUT=0; 
while [ "$OUTPUT" = 0 ]; do 
  OUTPUT=`$cmd | grep -c somestring`;
done

BASH версия функции также:

function run_until () {
  OUTPUT=0; 
  while [ "$OUTPUT" = 0 ]; do 
    OUTPUT=`$1 | grep -c $2`; 
  done
}

Ответ 3

Я удивлен, что я не видел краткий однострочный Perl, упомянутый здесь:

perl -e 'do { sleep(1); $_ = `command`; print $_; } until (m/search/);'

Perl - действительно хороший язык для таких вещей. Замените "команду" командой, которую вы хотите повторно запустить. Замените "поиск" тем, что вы хотите найти. Если вы хотите найти что-то с косой чертой, замените m/search/ на строку m#search на /es#.

Кроме того, Perl работает на множестве разных платформ, включая Win32, и это будет работать везде, где у вас установлена ​​Perl. Просто измените свою команду соответствующим образом.

Ответ 4

grep -c 99999 напечатает 99999 строк контекста для соответствия (я предполагаю, что этого будет достаточно):

while true; do /some/command | grep expected -C 99999 && break; done

или

until /some/command | grep expected -C 9999; do echo -n .; done

... это напечатает несколько хороших точек, чтобы указать прогресс.

Ответ 5

while (/bin/true); do
  OUTPUT=`/some/command`
  if [[ "x$OUTPUT" != "x" ]]; then
    echo $OUTPUT
    break
  fi

  sleep 1
done

Ответ 6

EDIT: Мой первоначальный ответ предполагал, что "некоторая строка" означает "любая строка". Если вам нужно искать конкретный, Perl, вероятно, ваш лучший вариант, поскольку почти ничего не может побить Perl, когда дело доходит до соответствия REGEX.

Однако, если вы не можете использовать Perl по какой-либо причине (вы можете ожидать, что Perl будет присутствовать в большинстве дистрибутивов Linux, но никто не заставляет пользователя его устанавливать, хотя Perl может быть недоступен), вы можете сделать это с помощью помощь grep. Однако некоторые из решений grep, которые я видел до сих пор, являются субоптимальными (они медленнее, чем это было необходимо). В этом случае я предпочел бы сделать следующее:

MATCH=''; while [[ "e$MATCH" == "e" ]]; do MATCH=`COMMAND | grep "SOME_STRING"`; done; echo $MATCH

Замените COMMAND на фактическую команду для запуска и SOME_STRING со строкой для поиска. Если SOME_STRING находится на выходе COMMAND, цикл остановится и распечатает вывод, где найден SOME_STRING.

ОРИГИНАЛЬНЫЙ ОТВЕТ:

Возможно, это не лучшее решение (я не хороший программист bash), но он будет работать:-P

RUN=''; while [[ "e$RUN" == "e" ]]; do RUN=`XXXX`; done ; echo $RUN

Просто замените XXXX на ваш командный вызов, например. попробуйте использовать "echo", и он никогда не вернется (поскольку echo никогда не печатает ничего в stdout), однако, если вы используете "echo test", он сразу завершится и, наконец, распечатает тест.

Ответ 7

CONT=1; while [ $CONT -gt 0 ]; do $CMD | tee -a $FILE | grep -q $REGEXP; CONT=$? ; done

Команда tee может захватывать stdout в канале, в то же время передавая данные, а -a делает это добавлением к файлу, а не переписывает его каждый раз. grep -q будет return 0, если было совпадение, 1 в противном случае и ничего не записывает в stdout. $? - это возвращаемое значение предыдущей команды, поэтому $CONT будет возвратным значением grep в этом случае.

Ответ 8

Простым способом сделать это будет

until `/some/command`
do
  sleep 1
done

Обратные элементы вокруг команды делают тест until для вывода некоторого вывода, а не для проверки значения выхода команды.