Warpling
Warpling

Reputation: 2115

What is the easiest way to "detach/daemonize" a Bash script?

What I am trying to do is write a Bash script that sleeps for a set amount of time before using the mac say command to speak some text.

I'd like to be able to run the command and then close the terminal so it will still speak at the set time. I've looked into nohup, detach, launchd, and putting the process in the background, but all of these solutions still result in the process being terminated once the terminal is closed. Should I somehow make some sort of zombie child process to do this? What is the best solution? Thank you

# Simple Example of main code
sleep 10;
say hello;
exit;

Upvotes: 18

Views: 30691

Answers (8)

tobiasBora
tobiasBora

Reputation: 2412

All the solution here are very good, but they don't provide an easy way to "look" what happen in the program without doing a redirection that would fill the hard drive.

Using screen you can then very easily run a script, close your terminal/ssh session, and then come back latter, and "attach" again to the script. Do do that it's pretty easy.

Install

First install screen:

sudo apt-get install screen

Detach

and then put in your bash file

#!/usr/bin/env bash
screen -S myscreen -d -m bash -c 'ls; exec bash'

(replace ls with your program) It will create (-S) a "screen" named myscreen, and detach it (-d) by running the commands inside the ``-c``` option. Then if you want to connect later to this screen:

And attach later

screen -rd myscreen

if you want to list all screen currently running:

screen -ls

NB: if you want to close the screen when it's finished, remove the bash at the end of the command.

Upvotes: 1

sorpigal
sorpigal

Reputation: 26096

Depending on your definition of 'easy' the answer may be daemon.

Upvotes: 0

Piskvor left the building
Piskvor left the building

Reputation: 92772

nohup yourscript.sh 10 "hello" &

#     ^your script  ^^your parameter 1
#                      ^^^^^^^your parameter 2

This will detach the script from the terminal, and it won't be killed when the terminal closes. Note the & at the end; you can pass parameters to your script normally. Then yourscript.sh could be:

#!/bin/bash

sleep $1;
say "$2";
exit;

Upvotes: 13

Dennis Williamson
Dennis Williamson

Reputation: 360315

Your script could look like this:

#!/bin/bash
read -p "Text: " text
read -p "Delay: " delay
nohup bash -c "sleep $delay; say \"$text\" &"

Then you would run your script normally:

$ your_script
Text: hello
Delay: 10

and the outer script would exit, but the Sleep&Say™ would be left running in the background.

Upvotes: 3

darioo
darioo

Reputation: 47193

Use nohup yourscript.sh & as Piskvor suggested.

However, note that you won't be able to regain "control" of your process. Therefore, if you do need it, I suggest adding logging to a file so you know what your program is doing.

Killing your program might not be possible without kill -9, and that might be a bit brutal. If you don't want that, I'd suggest pooling for a file like end.txt every minute or so. If your program detects presence of such a file in it's working directory, it should exit gracefully.

Upvotes: 0

Will
Will

Reputation: 3660

If you do not start it with nohup, as already suggested, you would need to use disown as such ...

$ ./say-hello.sh &
[1] 12345
$ disown -h %1

You will need to make note of the job number (the second line in the example above, the job number is in the brackets and the other is the process id) so that you can pass it to disown.

Upvotes: 6

Jonathan Leffler
Jonathan Leffler

Reputation: 754420

Section 3.7.6 of the Bash Manual says:

The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the SIGHUP signal to a particular job, it should be removed from the jobs table with the disown builtin (see Section 7.2 [Job Control Builtins], page 88) or marked to not receive SIGHUP using disown -h.

So, using either nohup or disown should do the trick. Or you can do:

trap "" 1
sleep 10
say hello

That 'trap' line ignores signal 1, SIGHUP; you can probably also write 'trap "" HUP".

Upvotes: 14

Laurence Gonsalves
Laurence Gonsalves

Reputation: 143264

You need to use nohup and background together. I just tried this on OS-X to verify that it works:

nohup ./say-hello.sh &

Upvotes: 6

Related Questions