First: do you know how to run background task not attached to your user session?

Running a task attached to your current user session

Imagine you establish an ssh connection to your linux host, or you just log into your linux host desktop and open a terminal:

$> cp bigfile.zip /tmp/ &
[1] 738
$> # wait some time in order the copy is finished and then try:
$> ps -ef | grep 738
[1]+  Done                  cp bigfile.bz2 /tmp/
$>

Now try the same but just after running the copy command quit your session:

$> cp bigfile.zip /tmp/ &
[1] 758
$> # now close this session

Open another session terminal:

$> ps -ef | grep 758
$>

The process with ID 758 doesn’t exist and also it has not finished correctly. Why because running a background task like this, attach the process that runs the task to the session, and when you quit the session the process is killed.

Running a task not attached to your current session

The old way was to use the function nohup like this:

$> nohup cp bigfile.bz2 /tmp/ &

But today it is really simpler and more readable:

$> (cp bigfile.bz2 /tmp/ &)
$>

You can quit your session the task will continue to be executed in background on the host.

And if you want to track stdout and stderr from you background command (stderr and stdout are redirected inside cp_log.log):

$> (cp bigfile.bz2 /tmp/ >> cp_log.log 2>&1 &)
$>

Manage a background task in your shell script application

Let’s see with examples.

# Script func_in_background_V1.sh
#
#!/bin/bash

mytask() {
    taskLogger() {
        local content=$1
        echo "Background task mytask >>> $content"
    }

    local i
    i=0
    while :
    do
        if [ $i -gt 1000 ]; then
            taskLogger "1000 iterations I quit"
            exit 0
        fi
        taskLogger "I'm the background task and I'm doing my job"
        sleep1
        ((i++))
    done
}

mytask &
mytask_pid=$!
echo "mytask is running with process ID $mytask_pid"
$> ./func_in_background_V1.sh

If you quit your terminal session, the background task mystask is not killed.

Let’s see this other possibility.

in func_in_background_V1.sh change the call to mytask:

(mytask &)
echo "mytask is running but I can't know its process ID"

This second case is bad, because you can’t get the background task id from the parent process, the parent process has no control over the background task.

How to manage a background task from a parent task

You need to keep the child process ID in order to be able to kill it at the end of the parent task.

Proposal

Also, you can add a security in order to ensure your background task stop its execution when its parent task stops its execution. For example it can happen if there is an unhandled exception in the parent task, or if the parent task is kill by a kill command or by another process…

Then the solution proposed here is to give a mean to the background task to track the existence of its parent task. Let’s see how:

# Script func_in_background_V1.sh
#
#!/bin/bash

BASEDIR=$(dirname $0)
PID=$$ # process ID of the current task
touch $BASEDIR/$PID.task

mytask() {
    taskLogger() {
        local content=$1
        echo "Background task mytask >>> $content"
    }

    local i
    i=0
    while :
    do
        if [ ! -f $BASEDIR/$PID.task ]; then
            taskLogger "My parent task seems to have finish its work"
            taskLogger "Then I stop my work"
            exit 0
        fi
        if [ $i -gt 1000 ]; then
            taskLogger "1000 iterations I quit"
            exit 0
        fi
        taskLogger "I'm the background task and I'm doing my job"
        sleep 1
        ((i++))
    done
}

mytask &
mytask_pid=$!
echo "mytask is running with process ID $mytask_pid"

echo "I'm the parent task and if I want I can kill mytask with the command: kill $mytask_pid"

echo "I have finished, I let mytask continue its work"
rm $BASEDIR/$PID.task
$> ./func_in_background_V1.sh
mytask is running with process ID 4480
I'm the parent task and if I want I can kill mytask with the command: kill 4480
I have finished, I let mytask continue its work
Background task mytask >>> I'm the background task and I'm doing my job


$> Background task mytask >>> My parent task seems to have finish its work
Background task mytask >>> Then I stop my work


$>