• Uncategorized

About bash : Shell-script-that-can-check-if-it-was-backgrounded-at-invocation

Question Detail

I have written a script that relies on other server responses (uses wget to pull data), and I want it to always be run in the background unquestionably. I know one solution is to just write a wrapper script that will call my script with an & appended, but I want to avoid that clutter.

Is there a way for a bash (or zsh) script to determine if it was called with say ./foo.sh &, and if not, exit and re-launch itself as such?

Question Answer

The definition of a background process (I think) is that it has a controlling terminal but it is not part of that terminal’s foreground process group. I don’t think any shell, even zsh, gives you any access to that information through a builtin.

On Linux (and perhaps other unices), the STAT column of ps includes a + when the process is part of its terminal’s foreground process group. So a literal answer to your question is that you could put your script’s content in a main function and invoke it with:

case $(ps -o stat= -p $$) in
  *+*) main "[email protected]" &;;
  *) main "[email protected]";;
esac

But you might as well run main "[email protected]" & anyway. On Unix, fork is cheap.

However, I strongly advise against doing what you propose. This makes it impossible for someone to run your script and do something else afterwards — one would expect to be able to write your_script; my_postprocessing or your_script && my_postprocessing, but forking the script’s main task makes this impossible. Considering that the gain is occasionally saving one character when the script is invoked, it’s not worth making your script markedly less useful in this way.

If you really mean for the script to run in the background so that the user can close his terminal, you’ll need to do more work — you’ll need to daemonize the script, which includes not just backgrounding but also closing all file descriptors that have the terminal open, making the process a session leader and more. I think that will require splitting your script into a daemonizing wrapper script and a main script. But daemonizing is normally done for programs that never terminate unless explicitly stopped, which is not the behavior you describe.

I do not know, how to do this, but you may set variable in parent script and check for it in child:

if [[ -z "$_BACKGROUNDED" ]] ; then
    _BACKGROUNDED=1 exec "$0" "[email protected]" & exit
fi
# Put code here

Works both in bash and zsh.

the “tty” command says “not a tty” if you’re in the background, or gives the controlling terminal name (/dev/pts/1 for example) if you’re in the foreground. A simple way to tell.

Remember that you can’t (or, not recommended to) edit the running script. This question and the answers give workarounds.

I don’t write shell scripts a long time ago, but I can give you a very good idea (I hope). You can check the value of $$ (this is the PID of the process) and compare with the output of the command “jobs -l”. This last command will return the PID of all the backgrounded processes (jobs) and if the value of $$ is contained in the result of the “jobs -l”, this means that the current script is running on background.

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.