Breaking "tail -f" that is read by "while read" loop in HP-UX

I am trying to write a (sh -bourne shell) script that processes lines as they are written to a file. I am trying to do this by feeding the output tail -f

into a loop while read

. This tactic seems to be correct, based on my research on Google and also this question , which addresses a similar problem, but using bash.

From what I've read, it seems like I have to break out of the loop when the executable ceases to exist. This is not true. Actually, it seems the only way I can get out of this is by killing the process in another session. tail

seems to work fine, otherwise testing with this:

touch file
tail -f file | while read line
do
  echo $ line
done

The data I add to file

in another session is displayed as soon as the file from the above processing loop.

This is HP-UX B.11.23 version.

Thanks for any help / understanding you can provide!

0


source to share


5 answers


If you want to break out when your file no longer exists, just do it:

 test -f file || break

      

Placing this in your loop should break out.

The rest of the problem is how to split the read line as it blocks.



This can be done using a timeout like read -t 5 line. Then every 5 seconds, the read returns, and in case the file no longer exists, the loop is interrupted. Note: Create your loop so it can handle the case that the read time is not working but the file is still present.

EDIT: It seems that with a timeout, read returns false, so you can combine the test with a timeout, the result is:

  tail -f test.file | while read -t 3 line || test -f test.file; do 
          some stuff with $line
  done

      

+1


source


I don't know about HP-UX tail

, but GNU tail

has a parameter --follow=name

that will follow the file by name (by reopening the file every few seconds instead of reading from the same file a descriptor that won't detect if the file is detached) and exits when the file name used to open the file will be disabled:



tail --follow=name test.txt

      

0


source


If you are not using GNU tail , it will not be able to complete its action by following the file. The -f option is really only for interactive monitoring - indeed, I have a book that says "-f" is unlikely to be used in shell scripts. "

But to solve the problem, I'm not entirely sure if this is not a very difficult way to do it, but I figured that you can send tail to a FIFO, then have a function or script that would check the file for existence and kill off the tail if it was detached ...

#! / bin / sh

sentinel ()
{
    while true
    do
        if [! -e $ 1]
        then
            kill $ 2
            rm / tmp / $ 1
            break
        fi
    done
}       

touch $ 1

mkfifo / tmp / $ 1

tail -f $ 1> / tmp / $ 1 &

sentinel $ 1 $! &

cat / tmp / $ 1 | while read line
do
    echo $ line
done

There has been some naive testing and it looks like everything is fine and don't leave garbage around you.

0


source


I've never been happy with this answer, but I haven't found an alternative:

kill $(ps -o pid,cmd --no-headers --ppid $$ | grep tail | awk '{print $1}')

      

Get all processes that are children of the current process, find the tail, print the first column (tail pid) and kill it. Sin-damn-ugly indeed, that's life.

0


source


The following approach uses the command tail -f file

echos its process id plus a custom string prefix (here tailpid:

) in a loop while

where a custom string prefix string starts another (given one) while

that checks every 5 seconds if more exists file

. If not, it tail -f file

will be killed and the subshell containing the background loop while

will exit.

# cf. "The Heirloom Bourne Shell",
# http://heirloom.sourceforge.net/sh.html,
# http://sourceforge.net/projects/heirloom/files/heirloom-sh/ and
# http://freecode.com/projects/bournesh

/usr/local/bin/bournesh -c '
touch file
(tail -f file & echo "tailpid: ${!}" ) | while IFS="" read -r line
do
   case "$line" in
      tailpid:*) while sleep 5; do 
                       #echo hello; 
                       if [ ! -f file ]; then
                          IFS=" "; set -- ${line}
                          kill -HUP "$2"
                          exit
                       fi
                 done & 
                 continue ;;
   esac
   echo "$line"
done
echo exiting ...
'

      

0


source







All Articles