Bash script: `exit 0` fails to exit
bash, exit, freeze
Solution
Here's a smaller, self contained example that exhibits the same behavior:
echo foo > file
tail -f file | while read; do exit; done
The problem is that since each part of the pipeline runs in a subshell, `exit` only exits the `while read` loop, not the entire script.
It will then hang until `tail` finds a new line, tries to write it, and discovers that the pipe is broken.
To fix it, you can replace
tail -n 3 -f server.log | while read line
do
...
done
with
while read line
do
...
done < <(tail -n 3 -f server.log)
By redirecting from a process substitution instead, the flow doesn't have to wait for `tail` to finish like it would in a pipeline, and it won't run in a subshell so that `exit` will actually exits the entire script.
Problem
So I have this Bash script: ``` #!/bin/bash PID=`ps -u ...` if [ "$PID" = "" ]; then echo $(date) Server off: not backing up exit else echo "say Server backup in 10 seconds..." >> fifo sleep 10 STARTTIME="$(date +%s)" echo nosave >> fifo echo savenow >> fifo tail -n 3 -f server.log | while read line do if echo $line | grep -q 'save complete'; then echo $(date) Backing up... OF="./backups/backup $(date +%Y-%m-%d\ %H:%M:%S).tar.gz" tar -czhf "$OF" data echo autosave >> fifo echo "$(date) Backup complete, resuming..." echo "done" exit 0 echo "done2" fi TIMEDIFF="$(($(date +%s)-STARTTIME))" if ((TIMEDIFF > 70)); then echo "Save took too long, canceling backup." exit 1 fi done fi ``` Basically, the server takes input from a fifo and outputs to server.log. The fifo is used to send stop/start commands to the server for autosaves. At the end, once it receives the message from the server that the server has completed a save, it tar's the data directory and starts saves again. It's at the `exit 0` line that I'm having trouble. Everything executes fine, but I get this output: ``` srv:scripts $ ./backup.sh Sun Nov 24 22:42:09 EST 2013 Backing up... Sun Nov 24 22:42:10 EST 2013 Backup complete, resuming... done ``` But it hangs there. Notice how "done" echoes but "done2" fails. Something is causing it to hang on `exit 0`. ADDENDUM: Just to avoid confusion for people looking at this in the future, it hangs at the exit line and never returns to the command prompt. Not sure if I was clear enough in my original description. Any thoughts? This is the entire script, there's nothing else going on and I'm calling it direct from bash.