我发出该^z; bg; disown
序列是为了允许我关闭一个 ssh 会话,在这个会话中我正在运行一个非常重要的长期运行的进程。此进程将状态输出写入 stderr,即使在分离后它仍继续这样做(使用 lsof 验证,stderr fd 已打开以供读写)。
有没有办法确定该进程确实已被放弃(如果 shell 接收到 SIGHUP,则不会接收到 SIGHUP)?
答案1
在 Bash 中,disown
其自身发出的命令将从活动作业表中删除后台(通过bg
或&
)进程,并标记它们在注销时不会接收 SIGHUP。
您还可以将一个或多个作业传递给 disown,例如disown 1 3
。disown -h
如果您想将作业保留在表中,但在注销时仍不发送 SIGHUP,此标志很有用。
您可以通过发出命令来查看作业表jobs
。成功退出后台后,它将显示[1]+ command &
。放弃作业后,该作业将不再显示在作业表中,也不会在注销时被终止。您仍然可以通过ps ux
、top
和其他进程查看实用程序查看进程。
当一个作业被放弃之后,你可以等待它自然终止或者通过kill
PID 发送信号来停止它。
因为 Bash 只是从要终止的正在运行的作业列表中删除该作业,并且终端的 stdout 和 stderr 的文件句柄仍然打开,所以您将继续接收来自该作业的输出,直到您的终端设备关闭(当您注销时)。
例子:
# we start a command in the background
$ cat /dev/urandom > test &
[1] 18533
# we see our command is still running
$ jobs
[1]+ Running cat /dev/urandom > test &
# we disown the backgrounded job
$ disown 1
# notice it is no longer in the job table
$ jobs
我通常只disown
在运行可能长时间运行的命令(例如rsync
或cp
)后决定需要注销而不终止它时才使用。如果您知道要运行命令并注销,则可以通过将tee
其通过管道或 ing 传输到文件、使用 运行它nohup
或运行它screen
(这允许您重新获得命令的所有权/之后终止)来捕获输出。
例子:
# capture stdout and stderr to separate logs
cat /dev/urandom >stdout.log 2>stderr.log
# capture stdout and stderr to the same log, and display to stdout as well
cat /dev/urandom 2>&1 | tee output.log
# run a command under nohup (doesn't require a disown or job control support)
nohup cat /dev/urandom </dev/null
答案2
有没有办法确定该进程确实已被放弃(如果 shell 接收到 SIGHUP,则不会接收到 SIGHUP)?
如果最初调用该命令的 shell 仍然打开,那么您可以使用jobs
@lunixbochs 提到的方法来验证该过程是否不再显示。
如果您已经关闭了 shell,那么您应该会看到父 PID (PPID) 从父进程更改为 1(init PID)。我通常使用以下命令来验证这一点ps -elf | grep <command>
例如
➜ ~ sleep infinity
^Z
[1] + 3202480 suspended sleep infinity
➜ ~ bg
[1] + 3202480 continued sleep infinity
➜ ~ ps -elf | grep sleep
0 S user 3202480 1585476 0 80 0 - 1369 ia32_s 18:23 pts/1 00:00:00 sleep infinity
➜ ~ jobs
[1] + running sleep infinity
➜ ~ disown %1
➜ ~ jobs
现在杀死父 shell 并查看PPID
(注意现在是1
):
➜ ~ ps -elf | grep sleep
0 S user 3202480 1 0 80 0 - 1369 ia32_s 18:23 pts/1 00:00:00 sleep infinity
终止作业运行:
kill -9 <PID>