0

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.
4
  • BTW, your original code was logging the $? from date, not from java. Gotta be careful about order-of-operations. Commented Nov 17, 2019 at 20:54
  • As another aside, nohup only does any redirection at all if your program has handles on the TTY in the first place; if its handles are already on a file, nohup leaves them alone and doesn't open nohup.out at all. Commented Nov 17, 2019 at 21:03
  • Well spotted, I have corrected the order.
    – M.E.
    Commented Nov 17, 2019 at 21:13
  • give setsid (run a program in a new session) chance. You can combine it with nohup.
    – Wiimm
    Commented Nov 17, 2019 at 23:07

2 Answers 2

2

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
10
  • Yes I am specifically looking for the option of being able to disconnect the terminal, i.e. nohup
    – M.E.
    Commented Nov 17, 2019 at 20:47
  • You don't need nohup to disconnect from the terminal. exec </dev/null disconnects stdin from the terminal. exec >somefile.log 2>&1 disconnects stdout and stderr from the terminal. disown, another shell builtin, prevents propagation of HUP signals; combine those things, and you have everything nohup does, built into the shell itself; so nohup is effectively useless/needless overhead. Commented Nov 17, 2019 at 20:47
  • ...now, an interactive shell will also propagate HUP signals to children, which either using nohup or disown -h will suppress (the latter being a shell builtin), but a noninteractive interpreter (like one running a script!) doesn't do that in the first place. Commented Nov 17, 2019 at 20:49
  • So using exec </dev/null >>nohup.out 2>&1 effectively makes the process launched independent of the terminal? I thought that the java process launched by this script would have as parent the shell ID from the terminal, and if you disconnect that effectively you are killing the parent (and hence the childs).
    – M.E.
    Commented Nov 17, 2019 at 20:50
  • Killing a parent process does not automatically kill children; SIGTERMs don't propagate like that. Closing a terminal sends HUPs to processes with a handle on that terminal, but if you don't have a handle and you don't have a parent process that's explicitly propagating the signal, that's irrelevant. Commented Nov 17, 2019 at 20:52
0

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 ;)

2
  • (1) You don't need all the backslashes in that function -- inside a function definition newlines are perfectly valid unescaped. (2) $* is buggy -- it changes "argument one" "argument two" to argument one argument two; to avoid that, "$@" should be used instead. (3) function funcname() { merges the 1980s ksh syntax function funcname { and the standardized-since-1991 POSIX sh syntax funcname() { in a way that's incompatible with both legacy ksh and POSIX. Commented Mar 20 at 21:21
  • (4) See my answer -- nohup isn't actually doing anything here that bash itself can't do built-in. (5) $(which dolphin) --help is much slower than command dolphin --help (as which is an external executable, not part of the shell, in bash -- note that this is different in zsh -- and use of $() forks off a subshell, which has its own performance cost); the which use also adds bugs in some weird corner cases (like if the directory name the dolphin command is found in contains whitespace). Commented Mar 20 at 21:23

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