shell脚本5---信号处理

发布时间 2023-11-29 18:09:14作者: DoubleLi

信号的类别

信号 描述
1 SIGHUP 挂起进程
2 SIGINT 终止进程
3 SIGQUIT 停止进程
9 SIGKILL 无条件终止进程
15 SIGTERM 优雅的终止进程
17 SIGSTOP 无条件停止进程,但不是终止进程
18 SIGTSTP 停止或暂停进程,但不是终止进程
19 SIGCONT 继续运行停止的进程

默认情况下,bash shell会忽略收到的任何SIGQUIT(3)和SIGTERM(15)信号(正因为这样交互式shell才不会被意外终止)。但是bash shell会处理收到的SIGHUP(1)和SIGINT(2)信号。

如果bash shell收到SIGHUP信号,它会退出。但在退出之前,它会将信号传给shell启动的所有进程(比如shell脚本)。通过SIGINT信号,可以中断shell,Linux内核停止将CPU的处理时间分配给shell,当这种情况发生时,shell会将SIGINT信号传给shell启动的所有进程。

产生信号
  • 终止进程:ctrl+c
  • 暂停进程:ctrl+z,停止的进程继续保留在内存中,并能从停止的位置继续运行

在无条件终止作业时,开始不会得到任何反应。但下次有shell提示符时,你会看到一个消息说明作业已经被终止了。

$ sleep 100
^Z
[1]+ stopped sleep 100
$
$ kill -9 10650
$
[1]+ Killed sleep 100
$

方括号中的数字时shell分配的作业号。每当shell产生一个提示符时,它就会显示shell中已经改变状态的作业的状态。在你无条件终止一个作业后,下次强制shell生成一个提示符时,shell会产生一条消息,说明作业在运行时被无条件终止了。

捕捉信号

trap命令允许你来指定shell脚本要watch哪些linux信号并从shell中拦截。如果脚本收到了trap命令中列出的信号,它会阻止它被shell处理,而在本地处理。
trap命令的格式:

trap commands signals

signals多个信号用空格隔开。
以下例子用trap命令来捕捉SIGINT和SIGTERM信号

#!/bin/bash

trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT SIGTERM
count=1
while [ $count -le 10 ]
do 
    echo "Loop #$count"
    sleep 5
    count=$[ $count + 1 ]
done
echo this is the end of the program

当我们执行Ctrl+C时,shell脚本不会中断。

捕捉脚本的退出

要捕捉shell脚本的退出,只要在trap命令后加上EXIT信号就行。

#!/bin/bash
trap "echo Goodbye" EXIT

count=1
while [ $count -le 5 ]
do 
     echo "Loop #$count
      sleep 3
      count=$[ $count + 1 ]
done

执行这个脚本,在脚本执行完成退出前,会输出Goodbye。

移除捕捉
trap -- signals
jobs

参数列表

参数 描述
-l 列出进程的PID以及作业号
-n 只列出上次shell发出的通知后改变了状态的作业
-p 只列出作业的PID
-r 只列出运行中的作业
-s 只列出已停止的作业

jobs输出中会有加号和减号。带加号的作业会被当作默认作业。在使用作业控制命令时,如果未在命令行指定任何作业号,该作业会被当作操作对象。带减号的作业则会在默认作业完成后成为下一个默认作业。任何时候只有一个带加号和一个带减号的作业。

重启停止的作业

在bash作业控制中,可以将已停止的作业作为前台或者后台进程重启。前台进程会接管当前的工作终端。

  • bg <作业号> 重新在后台启动该作业
  • fg <作业号> 重新在前台启动该作业
nice 和 renice

nice命令允许在执行一个命令是调整它的调度优先级。优先级是一个整数值。从-20(最高优先级)到20(最低优先级)。默认情况下,bash shell以优先级0启动所有进程。

nice -n 10 ./test4 > /tmp/test4out &

renice可以改变已运行命令的优先级。

renice 10 -p <PID>

普通用户只能调整属于自己进程的优先级。并且只能降低优先级。
root可以调整任何进程的优先级到任意级别。

计划任务

如何设置一个计划任务在每月的最后一天执行?

00 12 * * * if [ `date +%d -d tomorrow` = 01 ];then <command>;fi