linux后台运行命令的两种方式
command &
适合场景:命令还未启动
./test &
Ctrl + z
适合场景: 命令已运行
# 运行命令
./test
# 挂起命令到后台,并暂停运行
Ctrl + z
# 查看后台运行的任务
jobs
# 将暂停的命令重新运行
bg %1
这两种方式存在的问题是会话关闭后可能会导致命令停止。
linux关闭会话保持命令运行
关闭会话,发生了什么
步骤1:系统发送Sighup信号给控制进程(通常为shell);
步骤2:控制进程停止,发送Sighup到前台进程和后台进程;
步骤3:子进程收到信号;
步骤4:子进程关闭当前进程;
测试方法
编写一个实时输出的脚本
vim test
#!/bin/bash
while true
do
# 输出当前时间到log文件
time=$(date "+%Y-%m-%d %H:%M:%S")
echo $time >> log
# 休息一秒
sleep 1s
done
chmod +x test
另外启动一个控制台实时查看log文件是否有更新
tail -f log
干涉步骤1,不发送Sighup信号给shell
从根源解决问题,不关闭终端,而是把当前shell隐藏起来。
终端复用软件
screen和tmux是一个终端复用软件,通过该软件能够使终端隐藏起来而不是关闭。
以tmux为例
# 进入tmux
tmux
# 执行命令
./test &
# 分离当前session,此时这个session就会进入到后台运行
tmux detach
# 重新进入会话
tmux detach -t 0
干涉步骤2,不发送信号给当前shell的子进程
不同的shell有不同的实现。
bash: huponexit off
这个是shell的配置,是否在终端退出时发出挂起信号?on为是,off为否
# 查看huponexit命令的状态
shopt | grep huponexit
# 开启终端退出挂起
shopt -s huponexit
# 关闭终端退出挂起
shopt -u huponexit
zsh: nohup
# 关闭终端退出挂起
setopt NOhup
# 开启终端退出挂起
setopt hup
干涉步骤3,子进程不接收父进程发送过来的信号
setsid
使用该命令运行的命令会运行在init进程中,这就使得命令的运行与当前的shell没有关系了
setsid ./test
# 使用pstree查看,发现进程在init进程上
pstree
nohup
忽略Sighup信号
nohup ./test.sh
disown
该命令需要set选项monitor处于开启状态时才能执行
# 查看monitor是否开启
set -o
# 若monitor on
将任务从当前jobs列表中移除并忽略Sighup信号,但是进程还属于当前shell
# 运行任务
./test &
# 查看任务
jobs
# 从当前shell移除作业
disown %1
干涉步骤4,接受父进程发送过来的Sighup信号但是不执行停止的操作
trap
trap 命令用于指定当前进程在接受到信号后将要采取的行动
# 设置接受到Sighup执行echo hello
trap "echo hello" HUP
# 查看当前shell pid
ps
# 发送Sighup信号给自己
kill -1 7830
因为trap的作用域是进程,所以编写一个脚本,使trap和要运行的脚本运行在同一个进程中。
#!/bin/bash
# 接受停止信号,“”表示但是不采取任何行动
trap "" HUP
# 执行命令
source ./test
# 或者
. ./test
# 或者
sh test