Linux中的disown命令

时间:2020-03-21 11:43:26  来源:igfitidea点击:

在Linux中执行长时间运行的过程是很正常的。
例如,假设我们正在编译一个非常大的程序,那将花费很长时间。
可能是数小时甚至数天。
因此,基本上,我们需要一种方法来使程序即使在注销服务器后也可以保持更长的运行时间。
换句话说,即使shell会话结束后,我们也希望程序继续运行。

我们可以使用bash shell的工具甚至功能来实现此目的。
在本文中,我们将讨论称为bash shell的bash shell这样的功能。

好吧,我们可能会想为什么我将其称为bash shell的功能?
这是因为disown命令本身是bash shell的一部分。
它基本上是一个类似于cd,pwd等的shell内置命令。

bash shell中有一个称为type的命令,我们可以使用该命令来查找命令是shell功能还是外部命令。
见下文。

root@localhost:~# type cd
cd is a shell builtin
root@localhost:~# type pwd
pwd is a shell builtin
root@localhost:~# type disown
disown is a shell builtin

好吧,命令类型本身就是bash shell的一部分。

root@localhost:~# type type
type is a shell builtin

在Linux操作系统中运行的每个进程都有父级和子级关系。
下面的文章可能有助于进一步了解Linux中的进程。

阅读:Linux中的流程管理和监视

让我们首先登录到Linux计算机,然后触发命令并将其置于后台,看看注销时会发生什么。

ubuntu@localhost:~$cat /dev/random > /dev/null &

上面的命令将启动一个进程并将其置于后台。
现在,让我们看看谁是我们触发的命令的父进程。
可以使用以下命令找到Linux中所有正在运行的进程的父进程。

ubuntu@localhost:~$ps xao pid,ppid,comm

这将显示pid和父进程ID,以及触发该进程的命令。
使用上面的命令,我们可以轻松找到进程的父进程ID(在这种情况下为cat命令)。

ubuntu@localhost:~$ps xao pid,ppid,comm | grep cat
11391 10659 cat /dev/random

因此,我们的cat命令的父进程ID为10659,这从about结果可以明显看出。
现在让我们看看实际上是10659.

ubuntu@localhost:~$ps aux | grep 10659
ubuntu   10659  0.0  0.1  22916  5380 pts/1    Ss   14:01   0:00 -bash
ubuntu   11401  0.0  0.0  10432   672 pts/1    S+   14:42   0:00 grep --color=auto 10659

从上面的输出中,我们可以清楚地看到10659是bash shell进程。
我们当前登录的shell会话。
我们从此shell会话触发的任何内容,bash shell进程都将成为父进程。
在我们的示例中,我们触发了cat命令,并且bash shell进程成为其父进程。

当我们注销shell程序时,shell程序进程将被终止。
这也将导致其所有子女也被杀害。

基本上,当我们从shell注销时,SIGHUP信号将发送到shell的所有子代。
因此,当我们注销时,cat命令也将被杀死。
让我们尝试退出shell,看看会发生什么。

ubuntu@localhost:~$logout
There are stopped jobs.
ubuntu@localhost:~$logout

在某些情况下,当我们尝试使用CTRL + D OR logout命令或者exit命令注销计算机时,shell会通过说有它所拥有的作业来警告我们,该作业当前已停止。
如果我们愿意注销,则必须再次执行CTRL + D OR注销命令或者退出命令。

现在再次登录到同一台机器,并查看cat命令进程是否仍然存在。
它不会在那里。
这是因为当我们注销时,子进程(cat命令)也从父shell收到了SIGHUP信号。

这里要注意的另一件重要事情是bash shell设置,名为huponexit。
默认情况下,几乎所有现代发行版均禁用此选项。

如果禁用了huponexit选项,则bash shell进程将不会在退出时向由shell启动的子进程发送SIGHUP信号。
我们可以使用称为shopt的bash内置命令在bash中切换此设置。

ubuntu@localhost:~$shopt
autocd             off
cdable_vars        off
cdspell            off
checkhash          off
checkjobs          off
checkwinsize       on
cmdhist            on
compat31           off
compat32           off
compat40           off
compat41           off
compat42           off
complete_fullquote    on

如果我们如上所述执行shopt命令,它将打印设置的当前状态(即启用或者禁用了某些功能)。
让我们看看名为huponexit的设置的状态。

ubuntu@localhost:~$shopt | grep hup
huponexit          off

我们可以使用以下命令启用此设置。

shopt -s huponexit

可以使用以下命令来禁用此功能(禁用将不会将SIGHUP信号发送到退出时由Shell启动的进程,这是一个好主意)

shopt -u huponexit

要使由shopt命令配置的设置永久化,我们需要在.bashrc文件(位于用户主目录内)中进行输入(只需输入带有必需选项的shopt commnd)。

因此,如果禁用了huponexit选项,会发生什么情况。
如果禁用它,则shell程序将不会向子进程发送SIGHUP信号(这意味着即使退出shell程序,进程和命令也将继续运行)。
因此,在这种情况下,使用disown命令变得无关紧要。

那么,在退出Shell之后触发的过程的父级是谁?
在shell退出后,INIT进程将成为我们触发的进程的父级。

有两种解决方案,即使退出启用了huponexit的shell,也可以保持进程运行。
我们可以使用nohup命令或者disown命令。

注销后,nohup命令需要放在要继续运行的命令之前。
nohup命令的基本语法是nohup命令&

但是,nohup命令对已经运行的进程不是很有帮助。
这是disown命令派上用场的地方。

disown命令适用于作业。
基本上,它处理与shell关联的作业表。
我们可以使用以下命令查看触发并保留在后台的当前正在运行的作业。
让我们首先启动旧的cat命令,然后在bash shell的作业列表中看到它。

ubuntu@localhost:~$cat /dev/random > /dev/null &
[1] 5154
ubuntu@ip-10-12-2-73:~$jobs
[1]+  Running                 cat /dev/random > /dev/null &

从上面的输出中我们可以看到,我们的命令正在后台运行,其作业ID号为1.
现在让我们为该作业启动disown命令,以防止其在退出时被杀死。

ubuntu@localhost:~$disown -h %1

jobs命令将显示所有正在运行的作业及其ID号。
可以针对我们感兴趣的任何作业ID触发disown命令。

不带任何选项的disown命令只会从作业表中删除最后一个作业(当前作业..最新作业)(它不会杀死进程..而只是将其从Shell的作业表中删除)。
请参阅以下示例。

ubuntu@localhost:~$ping google.com > /dev/null &
[1] 5175
ubuntu@localhost:~$jobs
[1]+  Running                 ping google.com > /dev/null &
ubuntu@localhost:~$cat /dev/random > /dev/null &
[2] 5176
ubuntu@localhost:~$jobs
[1]-  Running                 ping google.com > /dev/null &
[2]+  Running                 cat /dev/random > /dev/null &

因此,现在我们有两个正在运行的作业,并且在作业表中。
现在让我们执行disown命令(显示的内容删除了我们触发的最后一个作业。
在这种情况下,它是cat命令。

ubuntu@localhost:~$jobs
[1]-  Running                 ping google.com > /dev/null &
[2]+  Running                 cat /dev/random > /dev/null &
ubuntu@localhost:~$disown
ubuntu@localhost:~$jobs
[1]+  Running                 ping google.com > /dev/null &

我们还可以使用以下命令从作业表中删除当前正在运行的所有作业。

ubuntu@localhost:~$disown -a

使用以下命令只能从作业表中删除正在运行的作业。

ubuntu@localhost:~$disown -r