Linux中的信号——shell编程学习_八

21 篇文章 0 订阅

Linux中的信号

简单的说,Linux shell中的信号是解决如何对运行中的脚本进行干预以及如何控制脚本运行的时机的一种解决方法。

Linux中的信号

什么是信号?类似于cpu中中断机制,用来进行进程之间的异步通信。由一个进程发出,由另一个进程接收并处理。

使用man命令对signel信号进行查看。下面是部分常用的信号含义:

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

产生信号的方式:

  • 代码实现

  • 键盘组合键

    信号名快捷键含义
    SIGINTCtrl+C终止当前进程
    SIGSTPCtrl+Z暂停当前进程
  • shell命令

    killkillall命令,本质是传递一个信号给别的进程。

    使用man kill查看kill信息。

使用示例:

[root@shell mnt]# ping 172.25.254.111       //使用ping命令,然后`ctrl+z`暂停进程
PING 172.25.254.111 (172.25.254.111) 56(84) bytes of data.
64 bytes from 172.25.254.111: icmp_seq=1 ttl=64 time=0.176 ms
64 bytes from 172.25.254.111: icmp_seq=2 ttl=64 time=0.191 ms
^Z
[1]+  Stopped                 ping 172.25.254.111
[root@shell mnt]# ps axu |grep ping //使用ps命令可以看到ping命令还存在,进程PID为1068
root      1068  0.0  0.1 103248   708 pts/0    T    21:48   0:00 ping 172.25.254.111
root      1070  0.0  0.1 103244   832 pts/0    S+   21:48   0:00 grep ping
[root@shell mnt]# kill -9 1068      //使用kill命令,-9为选项表示无条件杀死 PID用来作为进程标识,表示用来操作哪个进程
[root@shell mnt]# ps axu |grep ping //进程消失
root      1072  0.0  0.1 103244   832 pts/0    S+   21:48   0:00 grep ping
[1]+  Killed                  ping 172.25.254.111

程序中信号处理

默认方式

遵循信号原本的含义进行处理。如果不指定任何的信号操作,系统会默认按照默认方式处理信号

忽略信号

自定义方式
  • 自定义方式捕捉处理信号

trap命令用来捕捉信号

脚本示例:

[root@shell signal]# cat trap_1.sh 
#!/bin/bash

trap "echo signal traped signal for ctrl+c" SIGINT  //trap命令使用方法 trap + "命令" + 信号关键字

count=1
while [ $count -le 10 ]     //当count小于10时,进入循环
do
    echo "loop # $count"        //输出数字
    sleep 2
    count=$[ $count + 1 ]       //数字自增
done
echo "loop done"        //输出loop done

执行测试:

可以看到当我们再在键盘上键入crtl+c时,已经不能中断进程,因为脚本中trap的定义捕获了ctrl+c

[root@shell signal]# bash trap_1.sh 
loop # 1
loop # 2
^Csignal traped signal for ctrl+c       //键盘键入一次crtl+c 脚本继续执行,并输出捕获内容
loop # 3
loop # 4
^Csignal traped signal for ctrl+c
loop # 5
loop # 6
loop # 7
loop # 8
loop # 9
loop # 10
loop done

trap也能捕捉到程序的退出状态

具体用法,是将上述脚本的SINGAL关键字改称EXIT

示例:

[root@shell signal]# cat trap_2.sh 
#!/bin/bash

trap "echo 'get exit status'" EXIT      //捕获退出状态

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

[root@shell signal]# bash trap_2.sh     //执行脚本
loop # 1
loop # 2
loop # 3
loop done
get exit status         //最后,成功捕捉到trap的退出状态。因为捕获到,所以输出这一行

在脚本中对已经添加的trap进行移除,即不想让trap在某一块继续捕获处理信号。则可以:

在执行捕捉后,代码添加trap - SIGNAL/EXIT即可。

示例:

[root@shell signal]# cat trap_3.sh 
#!/bin/bash

trap "echo 'get exit status'" EXIT  //标识捕获EXIT状态

count=1
while [ $count -le 3 ]
do
    echo "loop # $count"
    sleep 2
    count=$[ $count + 1 ]
done    
trap - EXIT             //在此声明,不再捕获EXIT状态,实现移除trap捕获

echo "loop done"

测试:

[root@shell signal]# bash trap_3.sh 
loop # 1
loop # 2
loop # 3
loop done
//可以看到最后没有捕捉EXIT状态

后台运行脚本

什么是后台运行脚本:即不运行在终端显示器上的进程,称之为后台进程,控制进程的脚本叫后台脚本。

命令格式:SCRIPT &

示例:

[root@shell signal]# bash bg_1.sh &
[2] 1214        //1214是进程的PID,2是作业号,即当前执行的任务
[root@shell signal]# loop # 1
loop # 2
loop # 3

[2]-  Done                    bash bg_1.sh  //键入回车键,才会显示出来,程序已经结束   

这里出现个作业号概念**

作业是用户提交给系统的一个任务。作业号就是任务的标识。

进程和作业的区别:

区别:进程是一个程序在一个数据集上的一次执行,而作业是用户提交给系统的一个任务。

关系:一个作业通常包括几个进程,几个进程共同完成一个任务,即作业。

用户提交作业以后,当作业被调度,系统会为作业创建进程,一个进程无法完成时,系统会为这个进程创建子进程。

同时运行多个进程:

[root@shell signal]# bash bg_1.sh &     //第一次运行脚本
[2] 1218        //第一个进程:PID,1218;作业号,2
[root@shell signal]# loop # 1
bash bg_1.sh &      //第二次运行脚本
[3] 1220        //第二个进程:PID,1220;作业号,3
[root@shell signal]# loop # 1
bash bg_1.sh &loop # 2  //第三次运行脚本,**注意**这里的loop # 2是上面进程的输出

[4] 1223            //第三个进程:PID,1223;作业号,4
[root@shell signal]# loop # 1
bash bg_1.sh &loop # 2  //第四次运行脚本

[5] 1226            //第四个进程:PID,1226;作业号,5
[root@shell signal]# loop # 1
loop # 3
loop # 2
loop # 3
loop # 2
loop # 3
loop # 3

[2]   Done                    bash bg_1.sh      //四个进程一次结束
[3]   Done                    bash bg_1.sh
[4]   Done                    bash bg_1.sh
[5]-  Done                    bash bg_1.sh

虽然,上述例子,在前台有输出。但是不占用当前终端的命令行,整个进程是在后台运行的。jobs可以查看作业号和状态。

将停止进程调到前台继续运行示例:

[root@shell signal]# jobs       //使用jobs查看到一个停止的进程
[1]+  Stopped                 bash bg_1.sh
[root@shell signal]# fg 1   //`fg 作业号`将停止的指定作业号的进程重新在前台启动;如果要在后台使用`bg`
bash bg_1.sh
loop # 2
loop # 3

将停止进程调到后台继续运行示例:

[root@shell signal]# bash trap_2.sh 
loop # 1
^Z          //执行trap_2.sh后,使用ctrl+z组合键,暂停进程
[1]+  Stopped                 bash trap_2.sh
[root@shell signal]# jobs 
[1]+  Stopped                 bash trap_2.sh
[root@shell signal]# bg 1       //back ground,使用bg 1命令唤醒上面暂停的进程,并后台执行进程
[1]+ bash trap_2.sh &
[root@shell signal]# loop # 2
loop # 3
loop done
get exit status

[1]+  Done                    bash trap_2.sh

作业的优先级:

可以通过数字({-20,19})来指定作业优先级,-20最高,19最低

nice命令可以进行优先级的设定,renice命令可以进行优先级的重新设定

示例:

[root@shell signal]# nice -n 10 bash trap_1.sh > fsx.txt & 
[1] 1264        //创建一个进程,优先级设置为10,-n指定优先级
[root@shell signal]# ps -al     //查看进程
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  1264  1016  0  90  10 - 26516 wait   pts/0    00:00:00 bash
0 S     0  1270  1264  0  90  10 - 25227 hrtime pts/0    00:00:00 sleep
4 R     0  1271  1016  0  80   0 - 27032 -      pts/0    00:00:00 ps
//可以看到进程的优先级(NI)为10
[root@shell signal]# nice -n 11 bash trap_1.sh > fsx.txt & 
[2] 1274        //创建一个新的进程,优先级设置为11
[root@shell signal]# ps -al //查看进程,出现一个10优先级进程(还没有运行结束),和11优先级的进程
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  1264  1016  0  90  10 - 26516 wait   pts/0    00:00:00 bash
0 S     0  1274  1016  0  91  11 - 26516 wait   pts/0    00:00:00 bash
0 S     0  1275  1274  0  91  11 - 25227 hrtime pts/0    00:00:00 sleep
0 S     0  1276  1264  0  90  10 - 25227 hrtime pts/0    00:00:00 sleep
4 R     0  1277  1016  0  80   0 - 27032 -      pts/0    00:00:00 ps

[root@shell signal]# ps -al     //运行结束,执行ps命令可以看到两个进程结束
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 R     0  1289  1016  0  80   0 - 27024 -      pts/0    00:00:00 ps
[1]-  Done                    nice -n 10 bash trap_1.sh > fsx.txt
[2]+  Done                    nice -n 11 bash trap_1.sh > fsx.txt

注意使用nice命令指定优先级有用户权限限制,普通用户并不能指定优先级过高的nice值(一般来说,普通用户最高可以指定的优先级为0)

如何改变正在运行的程序的优先级?使用renice命令,使用方法:

renice 级别号 -p PID

级别号为要更改的级别

-p选项执行操作的进程的PID

PID为指定的进程PID号

更改优先级示例:

[root@shell signal]# nice -n 11 bash trap_1.sh > fsx.txt &  //开始使用nice设置优先级为11并运行
[1] 1290
[root@shell signal]# ps -al
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  1290  1016  0  91  11 - 26516 wait   pts/0    00:00:00 bash
0 S     0  1291  1290  0  91  11 - 25227 hrtime pts/0    00:00:00 sleep
4 R     0  1292  1016  0  80   0 - 27032 -      pts/0    00:00:00 ps
[root@shell signal]# renice 10 -p 1290  //renice重新设置上面进程的优先级
1290: old priority 11, new priority 10  //提示旧优先级,和新优先级
[root@shell signal]# ps -al
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  1290  1016  0  90  10 - 26516 wait   pts/0    00:00:00 bash
0 S     0  1300  1290  0  90  10 - 25227 hrtime pts/0    00:00:00 sleep
4 R     0  1301  1016  0  80   0 - 27032 -      pts/0    00:00:00 ps

[root@shell signal]# ps -al
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 R     0  1315  1016  0  80   0 - 27024 -      pts/0    00:00:00 ps
[1]+  Done                    nice -n 11 bash trap_1.sh > fsx.txt

renice和nice类似,普通用户也不能设置比0更高的优先级

nohup命令

不挂断地运行命令(即当前的控制台关闭,从控制台执行的后台命令不结束),这样的目的需要使用nohup命令

示例:

[root@shell signal]# nohup bash trap_1.sh &     //在脚本执行前添加nobup命令,
[1] 1401
[root@shell signal]# nohup: ignoring input and appending output to `nohup.out'  //会有这样的提示
        //键入回车,跳出trap_1.sh
[root@shell signal]# ls     //使用ls命令查看,有一个nohup.out文件,里面内容就是脚本执行的输出
bg_1.sh  fsx.txt  nohup.out  trap_1.sh  trap_2.sh  trap_3.sh
[root@shell signal]# cat nohup.out  //nohup.out全部内容
loop # 1
loop # 2
loop # 3
loop # 4
loop # 5
loop # 6
loop # 7
loop # 8
loop # 9
loop # 10
loop done
//将后台脚本和控制台分离,不互相影响

定时运行脚本

在日常的服务器维护、应用程序维护时,需要定时的日志清理和操作。有一个定时的机制,来运行脚本实现目的。

这里可以指定时间方式运行

at命令

at命令用于在指定时间执行命令。at允许使用一套相当复杂的指定时间的方法。可以用相对时间法指定,也可以用绝对时间法指定。

这里使用到at命令,具体格式:

at [ -f filename ] time

时间格式(部分):

10:12

10:12~PM

now、noon、midnight、teatime

MMDDYY、MM/DD/YY、MM.DD.YY

Jul 14、DEC 22

now+24min

默认情况下,at命令会将标准输入和标准错误以邮件的方式发送给用户。在日常操作,可以标准输出重定向

示例:

[root@shell signal]# cat at_1.sh 
#!/bin/bash

exec 1>>atresult        //将标准输出重定向到当前目录的atresult文件中

echo "script run at `date`" //输出时间
echo "end script"           //输出脚本运行结束

测试1:

[root@shell signal]# at -M -f at_1.sh 00:41 //-M指定不邮件,-f指定执行的脚本文件
job 10 at 2018-04-17 00:41
[root@shell signal]# date       //当前系统时间为凌晨12点40分,为了实验效率,这里设定at命令执行在12点41
Tue Apr 17 00:40:39 EDT 2018
[root@shell signal]# cat atresult   //刚开始atresult文件中没有内容

[root@shell signal]# date
Tue Apr 17 00:40:49 EDT 2018
[root@shell signal]# cat atresult       //到12点41后,执行了at命令,atresult文件中被输出内容,即脚本执行结果

script run at Tue Apr 17 00:41:00 EDT 2018
end script

测试2:

[root@shell signal]# rm -rf atresult        //删除上次的输出结果文件
[root@shell signal]# at -M -f at_1.sh now+1min      //设置当前时间一分钟后执行at命令
job 11 at 2018-04-17 00:43
[root@shell signal]# cat atresult           //当前没有该文件
cat: atresult: No such file or directory
[root@shell signal]# cat atresult           //等待一分钟后,查看atresult内容
script run at Tue Apr 17 00:43:00 EDT 2018
end script

cron时间表

CRONTAB具体原理及使用方法在之前博客有记录,在此不过多赘述。

cron的问题:cron假系统7*24运行,但如果在cron指定的时间内,没有开机,就无法执行计划任务。

要解决这个问题,就要使用异步cron,即anacron,配置文件/etc/anacrontab

# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1       5       cron.daily              nice run-parts /etc/cron.daily
7       25      cron.weekly             nice run-parts /etc/cron.weekly
@monthly 45     cron.monthly            nice run-parts /etc/cron.monthly
//这里也读取的时cron的配置

启动时运行脚本

启动时运行分为:

  • 系统启动时运行:Linux启动时运行

  • shell启动时运行:当打开一个bash时启动的脚本

系统启动时

计算机启动过程在以前简单介绍过,不多赘述,这里主要讨论怎么在系统启动时,运行脚本。

自定义开机运行脚本,不同Linux发行版配置文件不同:

  • debian /etc/init.d/rc.local

  • Ubuntu /etc/rc.local

  • openSUSE /etc/init.d/boot.local

  • CentOS /etc/rc.d/rc.local

  • redhat /etc/rc.d/rc.local

本机时redhat6.5,查看/etc/rc.d/rc.local配置文件“:

#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

出错如何查看:将我们需要添加的命令放到改文件内。为了防止配置时出错,可以将标准输出和标准错误重定向到不同的文件中。

一般情况是,在外面写好脚本,在rc.locl文件中进行调用。

shell启动

这里要明确启动时,调用了那几个shell配置文件:

  • 启动本地bash

调用/etc/profile/host/用户/.bashrc

  • 通过ssh登陆

调用/etc/profile/host/用户/.bashrc

  • 通过ssh执行命令

不会经过login过程,即不会调用/etc/profile文件

本书共分五部分,详细介绍了shell编程技巧,各种UNIX命令及语法,还涉及了UNIX下的文字处理以及少量的系统管理问题。本书内容全面、文字简洁流畅,适合Shell编程人员学习、参考。 目 录 译者序 前言 第一部分 shell 第1章 文件安全与权限 1 1.1 文件 1 1.2 文件类型 2 1.3 权限 2 1.4 改变权限位 4 1.4.1 符号模式 4 1.4.2 chmod命令举例 5 1.4.3 绝对模式 5 1.4.4 chmod命令的其他例子 6 1.4.5 可以选择使用符号模式或绝对模式 7 1.5 目录 7 1.6 suid/guid 7 1.6.1 为什么要使用suid/guid 8 1.6.2 设置suid/guid的例子 8 1.7 chown和chgrp 9 1.7.1 chown举例 9 1.7.2 chgrp举例 9 1.7.3 找出你所属于的用户组 9 1.7.4 找出其他用户所属于的组 10 1.8 umask 10 1.8.1 如何计算umask值 10 1.8.2 常用的umask值 11 1.9 符号链接 12 1.9.1 使用软链接来保存文件的多个映像 12 1.9.2 符号链接举例 12 1.10 小结 13 第2章 使用find和xargs 14 2.1 find命令选项 14 2.1.1 使用name选项 15 2.1.2 使用perm选项 16 2.1.3 忽略某个目录 16 2.1.4 使用user和nouser选项 16 2.1.5 使用group和nogroup选项 16 2.1.6 按照更改时间查找文件 17 2.1.7 查找比某个文件新或旧的文件 17 2.1.8 使用type选项 17 2.1.9 使用size选项 18 2.1.10 使用depth选项 18 2.1.11 使用mount选项 18 2.1.12 使用cpio选项 18 2.1.13 使用exec或ok来执行shell命令 19 2.1.14 find命令的例子 20 2.2 xargs 20 2.3 小结 21 第3章 后台执行命令 22 3.1 cron和crontab 22 3.1.1 crontab的域 22 3.1.2 crontab条目举例 23 3.1.3 crontab命令选项 23 3.1.4 创建一个新的crontab文件 24 3.1.5 列出crontab文件 24 3.1.6 编辑crontab文件 24 3.1.7 删除crontab文件 25 3.1.8 恢复丢失的crontab文件 25 3.2 at命令 25 3.2.1 使用at命令提交命令或脚本 26 3.2.2 列出所提交的作业 27 3.2.3 清除一个作业 27 3.3 &命令 27 3.3.1 向后台提交命令 28 3.3.2 用ps命令查看进程 28 3.3.3 杀死后台进程 28 3.4 nohup命令 29 3.4.1 使用nohup命令提交作业 29 3.4.2 一次提交几个作业 29 3.5 小结 30 第4章 文件名置换 31 4.1 使用* 31 4.2 使用? 32 4.3 使用[...]和[!...] 32 4.4 小结 33 第5章 shell输入与输出 34 5.1 echo 34 5.2 read 35 5.3 cat 37 5.4 管道 38 5.5 tee 39 5.6 标准输入、输出和错误 40 5.6.1 标准输入 40 5.6.2 标准输出 40 5.6.3 标准错误 40 5.7 文件重定向 40 5.7.1 重定向标准输出 41 5.7.2 重定向标准输入 42 5.7.3 重定向标准错误 42 5.8 结合使用标准输出和标准错误 43 5.9 合并标准输出和标准错误 43 5.10 exec 44 5.11 使用文件描述符 44 5.12 小结 45 ... ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值