I have a process that is already running for a long time and don't want to end it.
How do I put it under nohup (that is, how do I cause it to continue running even if I close the terminal?)
yourExecutable &
and the outputs keep coming on the screen and Ctrl+C
does not seem to stop anything, just blindly type disown;
and press Enter
even if the screen is scrolling with outputs and you can't see what you're typing. The process will get disowned and you'll be able to close the terminal without the process dying.
Using the Job Control of bash to send the process into the background:
Ctrl+Z to stop (pause) the program and get back to the shell. bg to run it in the background. disown -h [job-spec] where [job-spec] is the job number (like %1 for the first running job; find about your number with the jobs command) so that the job isn't killed when the terminal closes.
Suppose for some reason Ctrl+Z is also not working, go to another terminal, find the process id (using ps
) and run:
kill -SIGSTOP PID
kill -SIGCONT PID
SIGSTOP
will suspend the process and SIGCONT
will resume the process, in background. So now, closing both your terminals won't stop your process.
disown %1
in the first terminal before closing it.
kwin
after a crash without thinking of the consequences). So if I stopped kwin, everything would have frozen and I had no possibilities to run bg
!
kill -SIGTSTP PID
and kill -SIGCONT PID
.
The command to separate a running job from the shell ( = makes it nohup) is disown
and a basic shell-command.
From bash-manpage (man bash):
disown [-ar] [-h] [jobspec ...] Without options, each jobspec is removed from the table of active jobs. If the -h option is given, each jobspec is not removed from the table, but is marked so that SIGHUP is not sent to the job if the shell receives a SIGHUP. If no jobspec is present, and neither the -a nor the -r option is supplied, the current job is used. If no jobspec is supplied, the -a option means to remove or mark all jobs; the -r option without a jobspec argument restricts operation to running jobs. The return value is 0 unless a jobspec does not specify a valid job.
That means, that a simple
disown -a
will remove all jobs from the job-table and makes them nohup
disown -a
removes all jobs. A simple disown
only removes the current job. As the man page in the answer says.
These are good answers above, I just wanted to add a clarification:
You can't disown
a pid or process, you disown
a job, and that is an important distinction.
A job is something that is a notion of a process that is attached to a shell, therefore you have to throw the job into the background (not suspend it) and then disown it.
Issue:
% jobs
[1] running java
[2] suspended vi
% disown %1
See http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ for a more detailed discussion of Unix Job Control.
Unfortunately disown
is specific to bash and not available in all shells.
Certain flavours of Unix (e.g. AIX and Solaris) have an option on the nohup
command itself which can be applied to a running process:
nohup -p pid
See http://en.wikipedia.org/wiki/Nohup
AIX
and Solaris
. "The AIX and Solaris versions of nohup have a -p option that modifies a running process to ignore future SIGHUP signals. Unlike the above-described disown builtin of bash, nohup -p accepts process IDs.". Source
Node's answer is really great, but it left open the question how can get stdout and stderr redirected. I found a solution on Unix & Linux, but it is also not complete. I would like to merge these two solutions. Here it is:
For my test I made a small bash script called loop.sh, which prints the pid of itself with a minute sleep in an infinite loop.
$./loop.sh
Now get the PID of this process somehow. Usually ps -C loop.sh
is good enough, but it is printed in my case.
Now we can switch to another terminal (or press ^Z and in the same terminal). Now gdb
should be attached to this process.
$ gdb -p <PID>
This stops the script (if running). Its state can be checked by ps -f <PID>
, where the STAT
field is 'T+' (or in case of ^Z 'T'), which means (man ps(1))
T Stopped, either by a job control signal or because it is being traced
+ is in the foreground process group
(gdb) call close(1)
$1 = 0
Close(1) returns zero on success.
(gdb) call open("loop.out", 01102, 0600)
$6 = 1
Open(1) returns the new file descriptor if successful.
This open is equal with open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)
. Instead of O_RDWR
O_WRONLY
could be applied, but /usr/sbin/lsof
says 'u' for all std* file handlers (FD
column), which is O_RDWR
.
I checked the values in /usr/include/bits/fcntl.h header file.
The output file could be opened with O_APPEND
, as nohup
would do, but this is not suggested by man open(2)
, because of possible NFS problems.
If we get -1 as a return value, then call perror("")
prints the error message. If we need the errno, use p errno
gdb comand.
Now we can check the newly redirected file. /usr/sbin/lsof -p <PID>
prints:
loop.sh <PID> truey 1u REG 0,26 0 15008411 /home/truey/loop.out
If we want, we can redirect stderr to another file, if we want to using call close(2)
and call open(...)
again using a different file name.
Now the attached bash
has to be released and we can quit gdb
:
(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q
If the script was stopped by gdb
from an other terminal it continues to run. We can switch back to loop.sh's terminal. Now it does not write anything to the screen, but running and writing into the file. We have to put it into the background. So press ^Z
.
^Z
[1]+ Stopped ./loop.sh
(Now we are in the same state as if ^Z
was pressed at the beginning.)
Now we can check the state of the job:
$ ps -f 24522
UID PID PPID C STIME TTY STAT TIME CMD
<UID> <PID><PPID> 0 11:16 pts/36 S 0:00 /bin/bash ./loop.sh
$ jobs
[1]+ Stopped ./loop.sh
So process should be running in the background and detached from the terminal. The number in the jobs
command's output in square brackets identifies the job inside bash
. We can use in the following built in bash
commands applying a '%' sign before the job number :
$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID PID PPID C STIME TTY STAT TIME CMD
<UID> <PID><PPID> 0 11:16 pts/36 S 0:00 /bin/bash ./loop.sh
And now we can quit from the calling bash. The process continues running in the background. If we quit its PPID become 1 (init(1) process) and the control terminal become unknown.
$ ps -f <PID>
UID PID PPID C STIME TTY STAT TIME CMD
<UID> <PID> 1 0 11:16 ? S 0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey 0u CHR 136,36 38 /dev/pts/36 (deleted)
loop.sh <PID> truey 1u REG 0,26 1127 15008411 /home/truey/loop.out
loop.sh <PID> truey 2u CHR 136,36 38 /dev/pts/36 (deleted)
COMMENT
The gdb stuff can be automatized creating a file (e.g. loop.gdb) containing the commands and run gdb -q -x loop.gdb -p <PID>
. My loop.gdb looks like this:
call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit
Or one can use the following one liner instead:
gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>
I hope this is a fairly complete description of the solution.
lsof
(the file handle's name is pipe
, not like /dev/pts/1
) or by ls -l /proc/<PID>/fd/<fd>
(this shows the symlink of the handle). Also subprocesses still can have not redirected outputs, which should be redirected to a file.
Simple and easiest steps
Ctrl + Z ----------> Suspends the process bg --------------> Resumes and runs background disown %1 -------------> required only if you need to detach from the terminal
disown -h %1
seems to avoid SIGHUP (completely detach process from terminal).
To send running process to nohup (http://en.wikipedia.org/wiki/Nohup)
nohup -p pid
, it did not worked for me
Then I tried the following commands and it worked very fine
Run some SOMECOMMAND, say /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1. Ctrl+Z to stop (pause) the program and get back to the shell. bg to run it in the background. disown -h so that the process isn't killed when the terminal closes. Type exit to get out of the shell because now you're good to go as the operation will run in the background in its own process, so it's not tied to a shell.
This process is the equivalent of running nohup SOMECOMMAND
.
ctrl + z - this will pause the job (not going to cancel!) bg - this will put the job in background and return in running process disown -a - this will cut all the attachment with job (so you can close the terminal and it will still run)
These simple steps will allow you to close the terminal while keeping process running.
It wont put on nohup
(based on my understanding of your question, you don't need it here).
On my AIX system, I tried
nohup -p processid>
This worked well. It continued to run my process even after closing terminal windows. We have ksh as default shell so the bg
and disown
commands didn't work.
Disclaimer: not an answer to this question, but you can start with this way in the first place.
This is modern and easy to use approach that allows managing multiple processes and has a nice terminal UI called hapless utility.
Install with pip install hapless
(or python3 -m pip install hapless
) and just run
$ hap run my-command # e.g. hap run python my_long_running_script.py
$ hap status # check all the launched processes
See docs for more info.
https://i.stack.imgur.com/M9BLx.png
Success story sharing
disown -h
perhaps is the more exact answer: "make disown behave more like nohup (i.e. the jobs will stay in your current shell's process tree until you exit your shell) This allows you to see all the jobs that this shell started." (from [quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/…)disown
, disown makes a process a daemon, which means standard input/output are redirected to /dev/null. So, if you plan to disown a job, its better to start it with logging into a file, e.g.my_job_command | tee my_job.log
disown
disassociates any pipes from the process. To reattach pipes, usegdb
as described in this thread. More specifically, this post.