M.E.
M.E.

Reputation: 5527

Is it possible to include a nohup command inside a bash script?

I have the following script:

#!/bin/bash

until java -jar "MyApplication.jar"; do
    echo "---"
    date
    echo "Application crashed with exit code $?. Waiting to respawn..." >&2
    sleep 60
    echo "Respawning.." >&2
done

Which basically will relaunch the java application if it does not terminate with an exit code 0.

I currently invoke this program with:

nohup ./myapplication.sh &

Where myapplication.sh is the file which contains above script.

I invoke this program from a given xterm under X11. I would like to be sure that the program keeps running even if I close the xterm or even terminate the whole X11 session.

Two questions related to this:

  1. Is it possible to include the nohup inside the script so I would just do: ./myapplication.sh & or ./myapplication.sh?
  2. Is it possible to redirect the nohup output to a file named myapplication_20191118_1723.out (i.e. the name and a timestamp -format of the timestamp is not that relevant-) instead of the default nohup.out? That file shall contain both std err and std out.

Upvotes: 0

Views: 4117

Answers (2)

Jay M
Jay M

Reputation: 4327

Simple answer: yes, of course you can!

How and why, I hear you say?

What if I need to run a program that does not play well with the console, e.g. the KDE file explorer, Dolphin?

When I run that from the command line and it prints out streams of internal Qt low level messages and mostly (if it's working correctly) these are meaningless and can be ignored. There are sometimes so many that they tend to make the terminal useless.

The following would be a way to stop that happening. And (if properly configured) could also be used to make it send the terminal output STDOUT to a named pipe, connected to a TCP server by using programs like netcat or the more capable socat.

This example is great if you want to run a noisy program from your login script.

function shush () { \
 QC="$1"; \
 shift; \
 nohup  "${QC}" $* >/dev/null 2>&1 & \
 disown; \
}

This make use of the bash function, alias and job control features. How this works:

  • We capture the 1st command parameter into ${QC} as that will be the command we want to run later
  • shift is used to drop the 1st paramter so it does not get passed again
  • nohup is used to disconnect stdin and stdout from the app
  • 2>&1 is used to redirect stderr to stdout
  • >/dev/null pipes stdout into /dev/null to get swallowed into nothingness.
  • The expansion of the string ${QC} is the command we will run, the quotes are there just in case the path has spaces in it.
  • $* expands all the remaining parameters, the same as $1 $2 $3 ....
  • the ampersand & makes the command into a background job
  • disown disassociates the last job from the terminal that started the job

nohup would normally create a file nohup.out, so the pipe to /dev/null prevent that.

disown is (usually) a shell built in statement and works by making the last background command (aka job) immune to signals such as HUP coming from the terminal. That means closing the terminal will not close the program.

BTW: I use this to allow me to run multiple GUI commands in Windows under WSL!

Now we can do...

> shush dolphin

Perhaps we would want to use it in a terminal too, we don't want to keep typing shush.

Then do this in ~/.bash_aliases

alias dolphin='shush dolphin' 

Now we can do both, the now shushed dolphin command works the same in a terminal or in a script, with or without command line parameters.

Ahh, I hear you say, but what if we need to undo that and "unshush" it, e.g. to use the --help command line option?

There are at least two ways. Quick and dirty, just bypass the alias using which

$(which dolphin) --help

Another way would be to modify the shush () function/script to extract the 2nd parameter (or scan all of them) and check if it is --noshush and/or has other parameters that need the terminal and act accordingly, but lets make that homework for the reader ;)

Upvotes: 0

Charles Duffy
Charles Duffy

Reputation: 295954

nohup doesn't actually do much of value.

  • It redirects stdin from /dev/null, if-and-only-if it's initially connected to a TTY.
  • It redirects stdout and stderr to nohup.out, if-and-only-if they're initially connected to a TTY.
  • It declines to propagate HUP signals to its child processes.

All of these things you can simply do yourself, without using nohup at all. (Moreover, a noninteractive shell doesn't propagate HUPs by default in the first place!).


#!/bin/bash

# Redirect stdin from /dev/null, and stdout and stderr to a log file
# (not having TTY handles is part of how/why programs started with nohup can survive
# a terminal dying).
#
# Note that printf %(...)T is a bash 4.3 feature
# ...you may need to use date if your bash is older.
printf -v logfile_name 'myapplication_%(%Y%m%d_%H%M%S)T' -1
exec </dev/null >"$logfile_name" 2>&1

# ignore any HUP signals we receive (even though we shouldn't get any regardless)
trap '' HUP

# prevent the JVM from getting any handles on X11, which would be broken on exit
unset DISPLAY

until java -jar "MyApplication.jar"; do
    retval=$?
    echo "---" >&2
    date >&2
    echo "Application crashed with exit code $retval. Waiting to respawn..." >&2
    sleep 60
    echo "Respawning.." >&2
done

Upvotes: 2

Related Questions