Do a tail -F until matching a pattern

后端 未结 10 1326
遥遥无期
遥遥无期 2020-11-28 09:21

I want to do a tail -F on a file until matching a pattern. I found a way using awk, but IMHO my command is not really clean. The problem is that I need to d

相关标签:
10条回答
  • 2020-11-28 10:08

    Try this:

    sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
    

    The whole command-line will exit as soon as the "EOF" string is seen in /tmp/foo.

    There is one side-effect: the tail process will be left running (in the background) until anything is written to /tmp/foo.

    0 讨论(0)
  • 2020-11-28 10:08

    Does this work for you?

    tail -n +0 -F /tmp/foo | sed '/EOF/q'
    

    I'm assuming that 'EOF' is the pattern you're looking for. The sed command quits when it finds it, which means that the tail should quit the next time it writes.

    I suppose that there is an outside chance that tail would hang around if the pattern is found at about the end of the file, waiting for more output to appear in the file which will never appear. If that's really a concern, you could probably arrange to kill it - the pipeline as a whole will terminate when sed terminates (unless you're using a funny shell that decides that isn't the correct behaviour).


    Grump about Bash

    As feared, bash (on MacOS X, at least, but probably everywhere) is a shell that thinks it needs to hang around waiting for tail to finish even though sed quit. Sometimes - more often than I like - I prefer the behaviour of good old Bourne shell which wasn't so clever and therefore guessed wrong less often than Bash does. dribbler is a program which dribbles out messages one per second ('1: Hello' etc in the example), with the output going to standard output. In Bash, this command sequence hangs until I did 'echo pqr >>/tmp/foo' in a separate window.

    date
    { timeout -t 2m dribbler -t -m Hello; echo EOF; } >/tmp/foo &
    echo Hi
    sleep 1   # Ensure /tmp/foo is created
    tail -n +0 -F /tmp/foo | sed '/EOF/q'
    date
    

    Sadly, I don't immediately see an option to control this behaviour. I did find shopt lithist, but that's unrelated to this problem.

    Hooray for Korn Shell

    I note that when I run that script using Korn shell, it works as I'd expect - leaving a tail lurking around to be killed somehow. What works there is 'echo pqr >> /tmp/foo' after the second date command completes.

    0 讨论(0)
  • 2020-11-28 10:11

    Use tail's --pid option and tail will stop when the shell dies. No need to add extra to the tailed file.

    sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
    
    0 讨论(0)
  • 2020-11-28 10:13
    sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
    

    Here the main problem is with $$. If you run command as is, $$ is set not to sh but to the PID of the current shell where command is run.

    To make kill work you need to change kill $$ to kill \$$

    After that you can safely get rid of --pid=$$ passed to tail command.

    Summarising, following will work just fine:

    /bin/sh -c 'tail -n 0 -f /tmp/foo | { sed "/EOF/ q" && kill \$$ ;}
    

    Optionally you can pass -n to sed to keep it quiet :)

    0 讨论(0)
提交回复
热议问题