Skip to content
Advertisement

Stop bash script from dying when exiting Java / Kotlin application

I’m starting a bash script from Kotlin, but the bash script stops running as soon as the Kotlin application exits.

val pr = ProcessBuilder("/home/vlad/liq", script, input).start()

Where script is a liquidsoap script and input is a parameter that’s being passed into the script

Typically, it’ll run something like the following:

./liq blah.liq http://somedomain.com:8090

liq then executes a liquidsoap script which is the first param and the second param is then used as a param for the liquidsoap script.

#!/bin/bash

nohup /usr/bin/liquidsoap $1 -- $2 > /dev/null 2>&1 &

# this causes syntax error
# nohup (/usr/bin/liquidsoap $1 -- $2 > /dev/null 2>&1 &)

This Kotlin application is run via java -jar dashboard.jar, while the application is running, that liquidsoap script is running, as soon as i exit the Kotlin application with Ctrl + C, that liquidsoap script also stops.

I was under the impression that nohup + & would spawn a new console thus keeping the script running even after the Kotlin application exits, but it’s not.

Any ideas on how to keep the script running even after my Kotlin application exits ?

Advertisement

Answer

nohup + & does not “spawn a new console”. It just creates a background process that ignores the hangup signal. See the Wikipedia article on nohup for more information.

I don’t know why killing the application kills the program that was run from it, but I can suggest a few things to try.

The double fork suggested by Nahuel Fouilleul is a good idea. An example of proper syntax is:

( nohup /usr/bin/liquidsoap $1 -- $2 </dev/null >/dev/null 2>&1 & )
sleep 1 # Wait to ensure that 'nohup' takes effect

The </dev/null isn’t necessary with nohup, but I’ve added it for consistency. The sleep 1 is an attempt to avoid a possible race condition between foreground and background processes.

If that doesn’t work, the setsid command, if you’ve got it, can further insulate a child process from its parent by putting it in a separate process group and session. Example usage is:

( setsid /usr/bin/liquidsoap $1 -- $2 </dev/null >/dev/null 2>&1 & )
sleep 1 # Wait to ensure that 'setsid' takes effect

See On writing a Linux shell script to safely detach programs from a terminal and Difference between nohup, disown and & for more information about setsid.

If you haven’t got setsid, or it doesn’t help, the next option is to use a daemon to run the command (making it completely unrelated to the process that sets it up to be run). The traditional way to do that is with the at command:

echo "/usr/bin/liquidsoap $1 -- $2" | at now

That requires that the atd daemon is running and that you have permission to use at. See Run command ‘at’ 5 seconds from now for more information about at.

The modern way to run a process from a daemon is to use systemd-run. See Shutdown, suspend require authentication when scheduled in at for an example of using systemd-run instead of at.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement