这篇笔记我们学习如何在Linux命令行中切换前台进程和后台进程。
我们都知道Linux下在Shell中执行一个程序流程(非Shell内置命令),父Shell进程会先fork一个子Shell进程,然后子Shell进程exec切换到我们要运行的程序上,被运行的程序stdin
、stdout
、stderr
都对接到了我们使用的Shell,因此这个程序能够接受我们的输入,并把信息输出到屏幕。
所谓的前台进程,意思就是我们当前Shell的输入输出都被程序进程占据了,把它切换到后台,可以方便我们用当前Shell继续执行其他命令,这在SSH连接到服务器上进行各种配置时经常用到。
为了介绍相关操作,这里我们用一个C语言程序来作为例子,假设编译后程序名为a.out
。
#include <stdio.h>
#include <unistd.h>
int main(void)
{
while(1)
{
printf("running...\n");
sleep(1);
}
return 0;
}
在前台进程运行的过程中,我们可以使用Ctrl+Z
暂停前台进程。
启动前台进程。
./a.out
在终端中按下Ctrl+Z
,可以看到类似如下输出内容。
^Z
[1] + 7180 suspended ./a.out
前台进程暂停后,我们可以使用jobs -l
命令,该命令可以查看当前所有的后台进程,-l
参数表示显示进程号,通常都会加上该参数。
此时我们可以使用命令bg %<job id>
,让暂停的进程继续在后台运行。
bg %1
我们会看到类似如下输出。
[1] + 7180 continued ./a.out
我们使用ps
命令可以查看进程的信息,下面例子中,输出的内容显示该进程的进程号是7180
,其父进程号是7122
(也就是我们的Shell)。
ps -ef | grep a.out
输出内容如下。
ubuntu 7180 7122 0 12:04 pts/2 00:00:00 ./a.out
查看父进程相关的信息。
ps -f -P 7122
输出内容如下。
UID PID PPID PSR C STIME TTY STAT TIME CMD
ubuntu 7122 4566 3 0 12:04 pts/2 Ss+ 0:00 zsh
注意:当有后台进程运行时,是无法退出当前Shell的,如果强行终止当前Shell进程,其下的子进程也就全终止了。下面例子中我们在Shell中输入了exit
,但相关的提示信息阻止我们退出。
# ubuntu @ ubuntu in ~/workspace/cpp/test1 [12:05:50]
$ exit
zsh: you have running jobs.
如果后台进程被从其他地方kill
掉,当前shell会有一个terminated
的提示。
[1] + 7180 terminated ./a.out
如果希望直接在后台启动进程,可以使用&
写法,下面是一个例子。
./a.out &
输出内容如下。
[1] 7462
运行程序的命令后面加上一个&
就可以自动把程序放到后台了。
使用命令fg %<job id>
,可以将后台进程调回前台。
fg %1
输出内容如下。
[1] + 7462 running ./a.out
使用disown %<job id>
可以指定当前Shell关闭后,指定的后台进程会自动挂到init
进程上。
disown %1
注:我用的系统是Ubuntu Gnome 16.04,这样操作后进程实际会挂到/sbin/upstart --user
上,按照PPID
一层层查上去都是和gdm
相关的进程,这个应该是Gnome图形界面下所有进程的父进程。
nohup
命令顾名思义能够让Shell运行的程序忽略SIGHUP
,该信号通常在用户退出登录或者终端关闭时发送给进程,因此关闭终端不会使得nohup
启动的后台进程中断。nohup
命令一般和&
连用,除此之外,如果程序有向stdout
或stderr
输出,nohup
会自动将其重定向到当前路径下的nohup.out
文件,如果我们想忽略输出,将其手动重定向到/dev/null
就行了。
nohup ./a.out>/dev/null &
输出内容如下。
[1] 7774
nohup: 忽略输入重定向错误到标准输出端
按下CTRL+Z
:暂停前台进程bg %<job id>
:将一个进程移到后台fg %<job id>
:将一个后台进程调回前台jobs -l
:查看当前shell管理的进程disown %<job id>
:当前Shell退出时,将后台进程挂到init
进程下nohup <cmd> &
:后台运行一个命令,并使其忽略SIGHUP
信号