linux后台运行与断开会话运行

linux后台运行命令的两种方式

Bilibili 视频

command &

适合场景:命令还未启动

1
./test &

Ctrl + z

适合场景: 命令已运行

1
2
3
4
5
6
7
8
# 运行命令
./test
# 挂起命令到后台,并暂停运行
Ctrl + z
# 查看后台运行的任务
jobs
# 将暂停的命令重新运行
bg %1

这两种方式存在的问题是会话关闭后可能会导致命令停止。

linux关闭会话保持命令运行

关闭会话,发生了什么

步骤1:系统发送Sighup信号给控制进程(通常为shell);

步骤2:控制进程停止,发送Sighup到前台进程和后台进程;

步骤3:子进程收到信号;

步骤4:子进程关闭当前进程;

测试方法

编写一个实时输出的脚本

1
vim test
1
2
3
4
5
6
7
8
9
#!/bin/bash
while true
do
# 输出当前时间到log文件
time=$(date "+%Y-%m-%d %H:%M:%S")
echo $time >> log
# 休息一秒
sleep 1s
done
1
chmod +x test

另外启动一个控制台实时查看log文件是否有更新

1
tail -f log

干涉步骤1,不发送Sighup信号给shell

从根源解决问题,不关闭终端,而是把当前shell隐藏起来。

终端复用软件

screen和tmux是一个终端复用软件,通过该软件能够使终端隐藏起来而不是关闭。

以tmux为例

1
2
3
4
5
6
7
8
# 进入tmux
tmux
# 执行命令
./test &
# 分离当前session,此时这个session就会进入到后台运行
tmux detach
# 重新进入会话
tmux detach -t 0

干涉步骤2,不发送信号给当前shell的子进程

不同的shell有不同的实现。

bash: huponexit off

这个是shell的配置,是否在终端退出时发出挂起信号?on为是,off为否

1
2
3
4
5
6
# 查看huponexit命令的状态
shopt | grep huponexit
# 开启终端退出挂起
shopt -s huponexit
# 关闭终端退出挂起
shopt -u huponexit

zsh: nohup

1
2
3
4
# 关闭终端退出挂起
setopt NOhup
# 开启终端退出挂起
setopt hup

干涉步骤3,子进程不接收父进程发送过来的信号

setsid

使用该命令运行的命令会运行在init进程中,这就使得命令的运行与当前的shell没有关系了

1
setsid ./test
1
2
# 使用pstree查看,发现进程在init进程上
pstree

image-20230306231841204

nohup

忽略Sighup信号

1
nohup ./test.sh

disown

该命令需要set选项monitor处于开启状态时才能执行

1
2
# 查看monitor是否开启
set -o

将任务从当前jobs列表中移除并忽略Sighup信号,但是进程还属于当前shell

1
2
3
4
5
6
# 运行任务
./test &
# 查看任务
jobs
# 从当前shell移除作业
disown %1

干涉步骤4,接受父进程发送过来的Sighup信号但是不执行停止的操作

trap

trap 命令用于指定当前进程在接受到信号后将要采取的行动

1
2
3
4
5
6
# 设置接受到Sighup执行echo hello
trap "echo hello" HUP
# 查看当前shell pid
ps
# 发送Sighup信号给自己
kill -1 7830

image-20230306233343787

因为trap的作用域是进程,所以编写一个脚本,使trap和要运行的脚本运行在同一个进程中。

1
2
3
4
5
6
7
8
9
#!/bin/bash
# 接受停止信号,“”表示但是不采取任何行动
trap "" HUP
# 执行命令
source ./test
# 或者
. ./test
# 或者
sh test