«grep -q» не выходит с «tail -f» - PullRequest
       3

«grep -q» не выходит с «tail -f»

7 голосов
/ 24 августа 2011

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

Вот что я пробую с tail -f и grep -q:

# tail -f logfile | grep -q 'Message to continue'

grep никогда не завершается итак что он ждет вечно, даже если в файле зарегистрировано «Сообщение для продолжения».

Когда я запускаю это без -f, кажется, что оно работает нормально.

Ответы [ 6 ]

9 голосов
/ 24 августа 2011

tail -f будет читать файл и отображать строки, добавленные позже, он не прекратит работу (если не отправлен сигнал типа SIGTERM). grep здесь не является блокирующей частью, tail -f есть. grep будет считывать данные из канала до тех пор, пока он не будет закрыт, но это никогда не происходит, потому что tail -f не завершает работу и сохраняет канал открытым.


Решением вашей проблемы может быть (не проверено и очень вероятно, что оно плохо работает):

tail -f logfile | while read line; do
  echo $line | grep -q 'find me to quit' && break;
done
4 голосов
/ 24 августа 2011

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

С простым файлом 'qqq'примерно 360 строк исходного кода C (различные программы объединены несколько раз), и, используя 'grep -q return', я наблюдаю:

  1. tail -n 300 qqq | grep -q return завершается почти сразу.
  2. tail -n 300 -f qqq | grep -q return не выходит.
  3. tail -n 300 -f qqq | strace -o grep.strace -q return не выходит, пока не прервано.Файл grep.strace заканчивается на:

    read(0, "#else\n#define _XOPEN_SOURCE 500\n"..., 32768) = 10152
    close(1)                                = 0
    exit_group(0)                           = ?
    

    Это заставляет меня думать, что grep завершился до того, как прерывание убивает tail;если он чего-то ждал, это означало бы, что он получил сигнал.

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

    #define _XOPEN_SOURCE 600
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdarg.h>
    #include <errno.h>
    #include <string.h>
    #include <stdio.h>
    
    static void err_error(const char *fmt, ...)
    {
        int errnum = errno;
        va_list args;
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        if (errnum != 0)
            fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
        exit(1);
    }
    
    int main(void)
    {
        int p[2];
        if (pipe(p) != 0)
            err_error("Failed to create pipe\n");
        pid_t pid;
        if ((pid = fork()) < 0)
            err_error("Failed to fork\n");
        else if (pid == 0)
        {
            char *tail[] = { "tail", "-f", "-n", "300", "qqq", 0 };
            dup2(p[1], 1);
            close(p[0]);
            close(p[1]);
            execvp(tail[0], tail);
            err_error("Failed to exec tail command");
        }
        else
        {
            char *grep[] = { "grep", "-q", "return", 0 };
            dup2(p[0], 0);
            close(p[0]);
            close(p[1]);
            execvp(grep[0], grep);
            err_error("Failed to exec grep command");
        }
        err_error("This can't happen!\n");
        return -1;
    }
    

    С файлом фиксированного размера, tail -f не собирается выходить - поэтому оболочка (bash), кажется, зависает.

  5. tail -n 300 -f qqq | grep -q returnторчал, но когда я использовал другой терминал, чтобы добавить еще 300 строк в файл qqq, команда вышла.Я интерпретирую это как происходящее, потому что grep вышел, поэтому, когда tail записал новые данные в канал, он получил SIGPIPE и завершился, и поэтому bash признал, что все процессы в конвейере были мертвы.

Я наблюдал одинаковое поведение как с ksh, так и с bash.Это говорит о том, что это не ошибка, а ожидаемое поведение.Тестирование в Linux (RHEL 5) на компьютере x86_64.

3 голосов
/ 31 июля 2013
tail -f logfile | grep  --max-count=1  -q 'Message to continue'

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

1 голос
/ 24 августа 2011

Я решил опубликовать это как ответ, так как он объясняет, почему команда завершается после второй записи в файл:

touch xxx
tail -f xxx | grep -q 'Stop'
ps -ef |grep 'grep -q'
# the grep process is there
echo "Stop" >> xxx
ps -ef|grep 'grep -q'
# the grep process actually DID exit
printf "\n" >> xxx
# the tail process exits, probably because it receives a signal when it 
# tries to write to a closed pipe
0 голосов
/ 21 февраля 2015

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

tail -n 1 -f /var/log/vmkernel.log |grep -m 1 IOMMUIntel >> / var / log / vmkernel.log

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

Если вам нравится хакерский взлом VMware, читайте больше здесь: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer

0 голосов
/ 24 августа 2011

Это потому, что tail с опцией -f (follow) не завершается и продолжает выводить grep.Ожидание строк в файле журнала, вероятно, будет проще с perl / python.

Запуск tail -f с модулем подпроцесса Python.Читайте вывод из tail в цикле, пока не увидите нужные строки, а затем выйдите из скрипта Python.Поместите это решение в свой скрипт оболочки.

Скрипт Python будет блокировать скрипт оболочки до тех пор, пока не будут видны нужные строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...