ChatGPT解决这个技术问题 Extra ChatGPT

How do I put an already-running process under nohup?

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

To anyone facing the same problem: Remember, that even if you type 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.

t
the Tin Man

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.


As the question was how to "put it under nohup",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/…)
How do I recover the job later? I can see it running using ps -e.
You can't see the output of a job after a 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
is it possible somehow to do something like 'my_job_command | tee my_job.log' after the command is already running?
disown disassociates any pipes from the process. To reattach pipes, use gdb as described in this thread. More specifically, this post.
P
Pungs

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.


Yes, thats a OS problem, kill does not work with Cygwin on Windows.
Also very useful if the job is started from another ssh session.
Just remember to do the disown %1 in the first terminal before closing it.
This is useful since I started a graphical interface with a console (in my case I started from konsole 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!
More easy to remember is just kill -SIGTSTP PID and kill -SIGCONT PID.
B
Bruno Bronosky

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.
t
the Tin Man

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.


D
Dale

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


Only for 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
C
Community

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.


Very informative indeed, and likely to work well in simple cases. But be warned, more complex cases may fail miserably. I had one of those today: My process had spawened another process that did the output (presumably to stderr), but had stdout hooked up for communication with its master. Redirecting the masters FDs was effectless because the child had inherited stderr, and closing the childs stdout failed the master that was waiting on the other end of the pipe. X-| Bettern know your processes well before you try this.
@cmaster You can check if a handle is redirected using 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.
The best answer on how to bring a detached process back to a terminal! Thanks a lot!
T
Thomas John

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


Carefull. This way process is still bound to terminal and will terminate if terminal is closed.
disown -h %1 seems to avoid SIGHUP (completely detach process from terminal).
t
the Tin Man

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.


D
Don't Panic

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


I think the behaviour for disown -a is to cut attachment with all jobs. However, it doesn't shutdown the stdin/stdout pipelines, which means that the process will still try to write (/read) from the terminal
t
the Tin Man

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.


M
Most Wanted

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


Does not provide a way how to send already running process into background, just another alternative to nohup, which is already mentioned in the question.