28

Is there way for a bash script to know if it is running in the foreground or background, and so it can behave slightly differently in each case?

30

Quoting man ps:

PROCESS STATE CODES

   Here are the different values that the s, stat and state output
   specifiers (header "STAT" or "S") will display to describe the state of
   a process.
   ...
   +    is in the foreground process group

So you could perform a simple check:

case $(ps -o stat= -p $$) in
  *+*) echo "Running in foreground" ;;
  *) echo "Running in background" ;;
esac
  • Surely anything invoked within $(...) is itself running in the background ....? I guess the process group is the important thing though, can't deny that it works. – Ed Randall Apr 4 at 14:09
2

Look at the file /etc/bash.bashrc".

The line that has "$PS1". Then do a "man bash" and look for the token PS1.

[ -z "$PS1" ] && return

exits a script that is not interactive.

1

All the previous solutions involve spawning processes, etc.. Very, very ugly, since .bashrc is called every time a bash shell launches, hence those solutions end launching 1000's of processes.

Much cleaner is asking bash itself: bash has a predefined variable $- that has "i" if its running in an interactive shell. For example, putting this into your .bashrc is much cleaner and much cheaper and, most importantly, will always work!

case "$-" in 

    *i*) # interactive shell

    ;;
esac
  • WHY ARE YOU YELLING? That looks very, very ugly ... – Pierre.Vriens Dec 14 '17 at 19:30
  • Simple, correct solution. – Ed Randall Apr 4 at 14:09
0

While you could think that checking if the shell is run in interactive mode will give the same result, in practise, this isn't. The concept looks similar but is actually different. You could run an interactive script in the background feeding input thanks to expect. Also, you could launch your script with bash with the -l argument. We cannot thus rely on the bash interactivity to check if our script is run in the background or in the foreground.

The answer from devnull is thus correct. To determine if the process is running in the foreground, the ps utility checks if the process group (pgrp) is the same as the process group id associated with the session's controlling terminal (tpgid) and adds a + sign in the output according to the process state.

Knowing that, we can definitely have a pure bash version of the test:

#!/usr/bin/env bash

IFS=$' '
retval=($(</proc/$$/stat))
IFS=$' \t\n'
if [[ "${retval[3]}" == "${retval[7]}" ]]; then
    echo "Background" > ./result.txt
else
    echo "Foreground" > ./result.txt
fi
exit

In the code above, we are outputting the result in a text file because stdout is not connected when a process is run in the background.

Please note the 4th and the 8th elements of the table respectively correspond to pgrp and tpgid (see the /proc/[pid]/stat section of the man page - man 5 proc).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.