19

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

8 Answers 8

15
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; 
Sign up to request clarification or add additional context in comments.

1 Comment

I neglected to mention that in my script the time and message are variable. If I run the command like this I never see my prompts nor can I input variables. :/
14

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".

1 Comment

Thank you, I wasn't aware of SIGHUP, but that makes sense. This works quite well for what I am trying to do. :)
7

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

nohup ./say-hello.sh & 

1 Comment

I had neglected to mention that in my script the time and message are variable. If I run the command like this I never see my prompts nor can I input variables. :/
6

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.

1 Comment

I am trying to make the script as self contained as possible so someone without bash or even terminal experience could run it. I suppose if I put this in another script though this would be feasible. Thank you!
3

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.

Comments

1

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.

Comments

0

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.

2 Comments

What about kill -15 - SIGTERM (can be caught & handled, and is intended for graceful termination) as opposed to kill -9 - SIGKILL (cannot be caught or ignored)?
@Piskvor: that's also possible, but you have to implement that behaviour. If that isn't a problem, it would be desirable.
0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.