Using a pidfile for control flow

:heavy_exclamation_mark: This post is older than a year. Consider some information might not be accurate anymore. :heavy_exclamation_mark:

I had to write recently some shell scripts that may be used for LSB like init.d services. It was a quite good experience and fresh up of my bash scripting skills.

One of the major requirements:

  • The application can only be started once. A second instance is not allowed.
  • To shutdown, we have to kill the process.

Here are my basic steps.

Define colors

I define some colours to illustrate the importance or status of some text.


Remember process id

By starting the application, we need to remember the process id (pid), that has be assigned. This pid will be stored in the file, named pidfile with the extension .pid. I recommend to use a variable for the location of the pidfile.

# place pid according to FHS in /var/run is not possible,
# since it is not started as root

If the application is started as root, put the pid under /var/run. If the application is running as different user and not started by root, you have to use a custom location.

Write pidfile

In the start function, execute the program.

start() {
    echo -e "Start $name using classpath $CLASSPATH \n"
    ${JAVA_HOME} -Djava.library.path=bin  \
    -classpath $CLASSPATH  \
    net.cinhtau.Starter logback.xml > /dev/null 2> "${SCRIPT_HOME}/$tan.err" &
    # Generate the pidfile from here. If we instead made the forked process
    # generate it there will be a race condition between the pidfile writing
    # and a process possibly asking for status.
    echo $! > $pidfile

The special parameter $! expands to the process ID of the most recently executed background (asynchronous) command. This pid is stored to the pidfile. See Bash Beginners Guide for more information about special parameters.

Check if process is still alive

The status function is essential for checking if the application, or more correctly the process id is still alive.

status() {
    if [ -f "$pidfile" ]; then
        pid=`cat "$pidfile"`
        if [ -e "/proc/$pid" ] ; then
            # process by this pid is running.
            # It may not be our pid, but that's what you get with just pidfiles.
            return 0
            return 2 # program is dead but pid file exists
        return 3 # program is not running

If the pidfile exists, we look for the pid under /proc, the process pseudo filesystem.

Stop application based on pidfile

To stop the application, we have to kill the process. If the application is successfully killed, we have to remove the pidfile.

stop() {
    # Try a few times to kill TERM the program
    if status; then
        pid=`cat "$pidfile"`
        echo "Killing $name (pid $pid)"
        kill -HUP $pid
        # Wait for it to exit.
        for i in `seq 1 5`; do
            echo "Waiting $name (pid $pid) to die..."
            status || break
            sleep 1
        if status ; then
            echo "$name stop failed; still running."
            echo "$name stopped."
            rm $pidfile

Use pidfile for control flow

This pidfile can now be used for the control flow, e.g. don’t start the application a second time, if the application is already running.

echo_success() {
  echo -n -e $"[$COLOR_SUCCESS  OK  $COLOR_NORMAL]"
  echo -ne "\r"
  return 0
case "$1" in
        if [ -e $pidfile ] ; then
            pid=$(cat $pidfile)
            echo -n -e "Application Component is already running under $COLOR_WARNING $pid $COLOR_NORMAL \n"
        stop ;;
    force-stop) force_stop ;;
        if [ $code -eq 0 ]; then
            echo_success && echo -e "\t $name is running, process `cat $pidfile`"
            echo -e " \t $name is $COLOR_WARNING not running $COLOR_NORMAL"
        exit $code
        stop && start
        echo "Usage: cinhtau.sh {start|stop|force-stop|status|restart}"
        exit 3
exit $?
Please remember the terms for blog comments.