Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ending tail -f started in a shell script

Tags:

bash

tail

I have the following.

  1. A Java process writing logs to the stdout
  2. A shell script starting the Java process
  3. Another shell script which executes the previous one and redirects the log
  4. I check the log file with the tail -f command for the success message.

Even if I have exit 0 in the code I cannot end the tail -f process.

Which doesn't let my script to finish. Is there any other way of doing this in Bash?

The code looks like the following.

function startServer() {   touch logfile   startJavaprocess > logfile &    tail -f logfile | while read line    do     if echo $line | grep -q 'Started'; then       echo 'Server Started'       exit 0     fi   done } 
like image 468
rangalo Avatar asked Jan 11 '10 11:01

rangalo


People also ask

How do you end a script in shell script?

To end a shell script and set its exit status, use the exit command. Give exit the exit status that your script should have. If it has no explicit status, it will exit with the status of the last command run.

How do you end the tail command?

include ssh-api ssh = getSSHConnection(); cmd = 'cd to folder'; ssh. command(cmd); cmd = 'tail -f log. txt'; ssh. command(cmd); wait for special event to occur... cmd = 'stop the tail now!

What is cat << EOF >>?

This operator stands for the end of the file. This means that wherever a compiler or an interpreter encounters this operator, it will receive an indication that the file it was reading has ended.

What is $() in bash script?

$() Command Substitution According to the official GNU Bash Reference manual: “Command substitution allows the output of a command to replace the command itself.


2 Answers

The best answer I can come up with is this

  1. Put a timeout on the read, tail -f logfile | read -t 30 line
  2. Start tail with --pid=$$, that way it'll exit when the bash-process has finished.

It'll cover all cases I can think of (server hangs with no output, server exits, server starts correctly).

Dont forget to start your tail before the server.

tail -n0 -F logfile 2>/dev/null | while read -t 30 line 

the -F will 'read' the file even if it doesn't exist (start reading it when it appears). The -n0 won't read anything already in the file, so you can keep appending to the logfile instead of overwriting it each time, and to standard log rotation on it.

EDIT:
Ok, so a rather crude 'solution', if you're using tail. There are probably better solutions using something else but tail, but I got to give it to you, tail gets you out of the broken-pipe quite nicely. A 'tee' which is able to handle SIGPIPE would probably work better. The java process actively doing a file system drop with an 'im alive' message of some sort is probably even easier to wait for.

function startServer() {   touch logfile    # 30 second timeout.   sleep 30 &   timerPid=$!    tail -n0 -F --pid=$timerPid logfile | while read line    do     if echo $line | grep -q 'Started'; then       echo 'Server Started'       # stop the timer..       kill $timerPid     fi   done &    startJavaprocess > logfile &    # wait for the timer to expire (or be killed)   wait %sleep } 
like image 100
falstro Avatar answered Oct 02 '22 23:10

falstro


Based on the answers I found here, this is what I've come up with.

It directly deals with tail and kills it once we've seen the needed log output. Using 'pkill -P $$ tail' should ensure that the right process is killed.

wait_until_started() {     echo Waiting until server is started     regex='Started'     tail logfile -n0 -F | while read line; do             if [[ $line =~ $regex ]]; then                     pkill -9 -P $$ tail             fi     done     echo Server is started } 
like image 29
David Resnick Avatar answered Oct 03 '22 01:10

David Resnick