1

How to write a bash script to exit tail -f filename.log if encountered a line in the file matches one of the following lines

Abaqus JOB filename COMPLETED

Abaqus/Analysis exited with errors

I know one can use Ctrl+C to exit tail -f but looking for automated way to do it.

Any assistance is appreciated.

phuclv
  • 2,001
  • 1
  • 16
  • 41
D. Jadan
  • 13
  • 2
  • Could you explain why you need to have an automated way of exiting something that is only used manually? I mean, you only use `tail -f` when you want to watch output in realtime, so why would you need to kill it automatically? – terdon Mar 01 '20 at 19:41
  • I don't understand exactly what you need. What do you want to automate? You have to describe in detail what exactly you need to achieve or what does not work. Do you want to list the contents of the LOG file in real time, but only the records with a particular string found? – s3n0 Mar 04 '20 at 16:48
  • 1
    Similar: [tail a log util keywords found or timeout](//unix.stackexchange.com/q/527543) or [make tail -f exit on a broken pipe](//unix.stackexchange.com/q/416150) – Stéphane Chazelas Mar 09 '23 at 15:20

3 Answers3

1
tail -f filename.log | sed '/Abaqus JOB filename COMPLETED/q'

As to "why would someone need this" appeals to the lack of imagination: because it may scroll too fast, and you may miss it. But you still want to check its progress. And you still want to have its latter part on your screen.

  • this doesn't work. Just like `tail -f | grep` which doesn't work, when `sed` exits `tail -f` still continues to run. However it may work in some newer GNU `tail`, not old GNU `tail` or busybox `tail` or BSD `tail` – phuclv Mar 09 '23 at 15:08
  • @phuclv It runs, until it tries to write something to the dead pipe. A possible improvement would be to explicitly send a `PIPE` signal to the command on the left from the right-hand-side when the pattern is detected. – Kusalananda Mar 09 '23 at 15:10
  • @Kusalananda no just try it and see, `tail -f` will only exit since GNU tail 8.28. See [make `tail -f` exit on a broken pipe](https://unix.stackexchange.com/a/416162/44425). It's frustrated because systems I work with use busybox tail or BSD tail. `tail -f filename.log | grep -m 1 -q 'Abaqus JOB filename COMPLETED'` also doesn't work – phuclv Mar 09 '23 at 15:18
  • @phuclv But my suggested improvement would still work: `tail -f file | { grep -q pattern && pkill -P "$$" tail; }` (using `grep` for shorter code). – Kusalananda Mar 09 '23 at 15:25
0
#!/bin/bash

p1="Abaqus/Analysis exited with errors"
p2="Abaqus JOB filename COMPLETED"

if tail /tmp/filename.log | grep -we "$p1" -we "$p2" > /dev/null 2>&1; then
    echo "pattern found"
    # ....do somenthing - what you need to do....
else
    echo "pattern not found"
fi

Endless loop:

while true; do
    if tail /tmp/filename.log | grep -we "$p1" -we "$p2" > /dev/null 2>&1; then 
       echo "pattern found !"
       # ....do something here....
       break
    fi
    sleep 1
done
s3n0
  • 170
  • 1
  • 8
0
sh -c 'echo "$$"; exec tail -f filename.log' | (
  IFS= read -r pid &&
    sed '/^Abaqus JOB filename COMPLETED$/q
         /^Abaqus\/Analysis exited with errors$/q' &&
    kill -s PIPE "$pid"
)

If we only did tail -f file.log | sed ...q, sed would quit upon seeing any of those lines, but then tail would only terminate (killed by a SIGPIPE) if ever it wrote anything to the pipe after that. And if that log file is never updated because the process that logs things to it has died, then that will never happen.

So here instead, we're sending the SIGPIPE (rather than a SIGTERM which with some shells cause an unwanted diagnostic message to be printed) manually. Using sh to pass the pid of tail (which reuses that of sh because of exec) along to the right hand side of the pipe in the beginning.

A perl equivalent:

sh -c 'echo "$$"; exec tail -f filename.log' | perl -lne '
  BEGIN {$pid = <> or die "No pid."}
  print;
  if ($_ eq "Abaqus JOB filename COMPLETED" ||
      $_ eq "Abaqus/Analysis exited with errors") {
    kill "PIPE", $pid;
    last;
  }'
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501