十一、脚本控制与计划任务(未完)

信号

Linux利用信号与运行在系统中的进程进行通信。

可以编写脚本使其收到特定信号时执行某些命令,从而控制shell脚本的操作。

linux常见信号

信号 描述
1 SIGHUP 挂起进程
2 SIGINT 终止进程
3 SIGQUIT 停止进程
9 SIGKILL 强制终止进程
15 SIGTERM 正常终止进程
17 SIGSTOP 强制停止进程
18 SIGTSTP 停止或暂停进程
19 SIGCONT 继续运行停止的进程

默认情况下bash shell会忽略收到的3,15信号,这样使交互式shell不会意外终止。

bash shell会接收1,2信号,如离开一个交互式shell之前,shell会把1信号即挂起信号传给所有由该shell启动的进程。

通过2信号,中断shell,Linux内核会停止为shell分配CPU处理时间,同样shell会把该信号传给由他启动的进程。

生成信号

linux使用键盘组合键生成停止或暂停两种基本信号

中断进程

ctrl+c生成2信号,终止进程

[root@tzPC ~]# sleep 100
^C

暂停进程

ctrl+z生成18信号,停止shell中运行的进程,停止进程会让程序继续保存在内存中并能从上次暂停的位置继续运行。

[1]是shell分配的作业号,shell把运行中的每个进程称为作业并为其分配唯一的作业号

[root@tzPC ~]# sleep 100
^Z
[1]+  已停止               sleep 100

jobs查看后台停止的进程

[root@tzPC ~]# jobs
[1]+  已停止               sleep 100

将后台停止的进程恢复到前台运行

[root@tzPC ~]# fg 1

 如果shell会话中有一个已停止的作业再退出shell时bash会提醒你

[root@tzPC ~]# sleep 100
^Z
[1]+  已停止               sleep 100
[root@tzPC ~]# exit
exit
有停止的任务。

使用ps -l查看已停止的作业

[root@tzPC ~]# ps -l
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  89099  89094  0  80   0 - 28912 do_wai pts/0    00:00:00 bash
0 T     0  91144  89099  0  80   0 - 26976 do_sig pts/0    00:00:00 sleep
0 R     0  91231  89099  0  80   0 - 37235 -      pts/0    00:00:00 ps

知道了已停止作业的PID,可以使用kill命令发送SIGKILL信号终止他

[root@tzPC ~]# kill -9 91144

捕获信号

trap命令

捕获信号并执行其他命令

语法格式

trap commands signals

 signals可以是数值或linux信号名

例:使用trap命令忽略SIGINT信号,捕获ctrl+c组合键

效果

[root@tzPC 16Unit]# bash test1.sh 
This is a test script
Loop #1
Loop #2
Loop #3
^CSorry! I have trapped Ctrl-C
Loop #4
Loop #5
^CSorry! I have trapped Ctrl-C
Loop #6
Loop #7
Loop #8
Loop #9
Loop #10

脚本

[root@tzPC 16Unit]# cat test1.sh
#!/bin/bash
#Testing signal trapping
trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT
echo This is a test script
count=1
while [ $count -le 10 ]
do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
done

捕获脚本退出

捕获shell脚本退出只要在trap命令后加上EXIT信号即可。

效果

[root@tzPC 16Unit]# cat test2.sh
#!/bin/bash
#Trapping the script exit
trap "echo 脚本执行完毕." EXIT
count=1
while [ $count -le 5 ]
do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
done

如果提前退出同样能捕获到EXIT信号

[root@tzPC 16Unit]# bash test2.sh
Loop #1
Loop #2
Loop #3
^C脚本执行完毕.

 修改或移除捕获

例:修改捕获命令

[root@tzPC 16Unit]# bash test3.sh
Loop #1
Loop #2
^CSorry...Ctrl+C is trapped.
Loop #3
Loop #4
Loop #5
Second #1
^CI modified the trap!
Second #2
Second #3
Second #4
Second #5

脚本

[root@tzPC 16Unit]# cat test3.sh
#!/bin/bash
#Modifying a set trap
trap "echo 'Sorry...Ctrl+C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
done
trap "echo 'I modified the trap!'" SIGINT
#这里修改了捕获到SIGINT的命令
count=1
while [ $count -le 5 ]
do
        echo "Second #$count"
        sleep 1
        count=$[ $count + 1 ]
done

删除捕获,在trap跟信号名称之间加--即可

trap -- SIGINT
或者
trap - SIGINT

脚本

[root@tzPC 16Unit]# cat test3.sh
#!/bin/bash
#Modifying a set trap
trap "echo 'Sorry...Ctrl+C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
done
trap - SIGINT
#或者trap -- SIGINT同样的效果
echo "I just removed the trap"
count=1
while [ $count -le 3 ]
do
        echo "Second #$count"
        sleep 1
        count=$[ $count + 1 ]
done

后台模式运行脚本

后台运行的脚本echo默认输出到显示器,最好重定向到文件里,不然会让人头昏脑胀,哈哈

运行多个后台作业

[root@tzPC 16Unit]# bash test4.sh &
[2] 89870
[root@tzPC 16Unit]# bash test5.sh &
[3] 90239
[root@tzPC 16Unit]# bash test6.sh &
[4] 90421

ps查看

每一个后台进程都和终端会话pts/0终端联系在一起,如果终端会话退出那么后台进程也会退出

[root@tzPC 16Unit]# ps
   PID TTY          TIME CMD
 77372 pts/0    00:00:00 bash
 89870 pts/0    00:00:00 bash
 89872 pts/0    00:00:00 sleep
 90239 pts/0    00:00:00 bash
 90240 pts/0    00:00:00 sleep
 90421 pts/0    00:00:00 bash
 90422 pts/0    00:00:00 sleep
 92024 pts/0    00:00:00 ps
115344 pts/0    00:00:00 bash

在非控制台下运行脚本

即使退出终端也让脚本一直运行的方法

之前有些过一篇笔记screen命令就可以做到

传送门:https://www.cnblogs.com/tz90/p/13289340.html

 书里讲的nohup命令

nohup命令会阻断所有发送给该进程的SIGHUP信号,也就是关闭session的信号。

运行脚本,此时session窗口假设为1

[root@tzPC 16Unit]# cat test4.sh
#!/bin/bash
count=1
while true
do
        echo "hello,$count"
        sleep 2
        count=$[ $count + 1 ]
done
[root@tzPC 16Unit]# nohup bash test4.sh
nohup: 忽略输入并把输出追加到"nohup.out"

打开另外一个session窗口2查看进程

[root@tzPC ~]# ps aux | fgrep test4.sh
root      22674  0.0  0.1 113132  1416 pts/0    S+   16:36   0:00 bash test4.sh
root      23685  0.0  0.0 112676   896 pts/2    R+   16:37   0:00 grep -F --color=auto test4.sh

关闭session1窗口,再次查看进程发现进程还在

nohup命令会解除session跟进程的关联也就是说关闭终端nohup命令执行的命令依旧在后台执行,这样造成nohup命令不再通STDOUT和STDERR描述符联系在一起,也就输出不到屏幕上。

这时nohup命令会自动将STDOU和STDERR消息重定向到当前目录下名为nohup.out文件中。

参考:https://blog.csdn.net/hl449006540/article/details/80216061

 作业控制

作业停止后可以使用kill命令终止该进程,要重启停止的进程需要发送SIGCONT信号。

启动、停止、终止以及恢复作业的功能统称为作业控制

查看作业

jobs可以查看正在处理的作业

脚本案例

[root@tzPC 16Unit]# cat test10.sh
#!/bin/bash
#Test job control
echo "Script Process ID: $$"
count=1
while [ $count -le 10 ] 
do
        echo "Loop #$count"
        sleep 10
        count=$[ $count + 1 ]
done
echo "End of script..."

运行脚本使用Ctrl+Z停止脚本

[root@tzPC 16Unit]# bash test10.sh
Script Process ID: 63760
Loop #1
^Z
[1]+  已停止               bash test10.sh

同样运行脚本使用&在后台进程中启动

这里将输出重定向到文件,避免头昏脑胀哈哈(我喜欢书里的这句话)!

[root@tzPC 16Unit]# bash test10.sh > test10.out &
[2] 64666

使用jobs查看

[root@tzPC 16Unit]# jobs
[1]+  Stopped                 bash test10.sh
[2]-  Running                 bash test10.sh > test10out &

jobs -l 选项查看作业的PID

[root@tzPC 16Unit]# jobs -l
[1]+ 68838 Stopped                 bash test10.sh
[2]- 68855 Running                 bash test10.sh > test10out &

上图所示,带+的作业是默认作业,在使用未指定作业号的作业控制命令时,该作业会被当初作业控制命令的操作对象。

带-的作业会成为下一个默认作业。

任何时候都只有一个带加号跟带减号的作业。

jobs常用命令参数

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

重启停止的作业

bg命令可以将已停止的作业作为后台进程重启

[root@tzPC 16Unit]# bash test10.sh >test10out
^Z
[1]+  Stopped                 bash test10.sh > test10out
[root@tzPC 16Unit]# jobs
[1]+  Stopped                 bash test10.sh > test10out
[root@tzPC 16Unit]# bg
[1]+ bash test10.sh > test10out &
[root@tzPC 16Unit]# jobs
[1]+  Running                 bash test10.sh > test10out &

因为该作业时默认作业所以bg后面不用加作业号

fg命令可以将已停止的作业作为前台进程重启。

[root@tzPC 16Unit]# jobs
[1]+  Stopped                 bash test10.sh > test10out
[root@tzPC 16Unit]# fg 1
bash test10.sh > test10out

 谦让度

  1. 调度优先级时内核分配给进程的CPU时间,优先级越高进程占用CPU的时间也就越多
  2. 调度优先级是个整数值
  3. 取值范围从-20(最高优先级)到+19(最低优先级)
  4. 由shell启动的所有进程调度优先级默认都相同,都为0
  5. 需要root权限

nice命令

-n参数修改优先级

[root@tzPC 16Unit]# nice -n 10 bash test4.sh >test4out &
[1] 72440

查看优先级NI

[root@tzPC 16Unit]# ps -p 72440 -o pid,ppid,ni,cmd
   PID   PPID  NI CMD
 72440  68701  10 bash test4.sh

renice命令

用于更改系统上已经运行命令的优先级,需要用到已运行命令进程的PID

  1. 只能对属主进程执行renice
  2. 普通用户只能降低进程优先级
  3. root用户可以调高跟降低进程优先级
[root@tzPC 16Unit]# bash test5.sh &
[1] 73522
[root@tzPC 16Unit]# ps -p 73522 -o pid,ppid,ni,cmd
   PID   PPID  NI CMD
 73522  68701   0 bash test5.sh

[root@tzPC 16Unit]# renice -n 10 -p 73522
73522 (process ID) old priority -10, new priority 10
[root@tzPC 16Unit]# ps -p 73522 -o pid,ppid,ni,cmd
   PID   PPID  NI CMD
 73522  68701  10 bash test5.sh

定时运行作业

  1. at(一次性执行)
  2. cron(定期执行)
  3. anacron(定期执行)

用at命令计划执行脚本

  1. 必须运行atd服务
  2. atd守护进程会每隔60秒检查/var/spool/at目录下文件,并同时检查文件设置的运行时间,如果跟当前时间匹配,则运行。
  3. 如果错过指定的时间,at命令会在第二天指定时间运行文件。

启动atd服务并加入开机启动项

[root@tzPC 16Unit]# systemctl start atd #必须启动atd服务
[root@tzPC 16Unit]# systemctl enable atd #加入开机启动项

at命令格式

at -f filename time

time格式

10:15

10:15 PM

now、noon、midnight、teatime(4 PM)

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

Jul 4、Dec 25

时间增量(当前时间+25min、明天10:15PM、10:15+7天)

优先级

支持26中不同的优先级,以小写字母a-z和大写字母A-Z标识,默认为a优先级

a的优先级最高,z的优先级最低

使用-q参数指定优先级

at命令的输出

脚本文件的输出会发送到该用户的邮件

案例

-f指定运行脚本文件,now表示立刻执行该脚本

[root@tzPC 16Unit]# cat test13.sh
#!/bin/bash
#Test using at command
echo "This script ran at $(date +%B%d,%T)" >test13out
sleep 5
echo "This is the script's end..." >>test13out

[root@tzPC 16Unit]# at -f test13.sh now
job 4 at Fri Aug 21 16:40:00 2020

注意:最好将脚本文件的输出重定向到文件,因为如果没有安装sendmail,脚本的输出结果就获取不了

列出等待中的作业

[root@tzPC 16Unit]# at -M -f test10.sh teatime
job 5 at Sat Aug 22 16:00:00 2020
[root@tzPC 16Unit]# at -M -f test10.sh tomorrow
job 6 at Sat Aug 22 16:47:00 2020
[root@tzPC 16Unit]# at -M -f test10.sh 13:30
job 7 at Sat Aug 22 13:30:00 2020
[root@tzPC 16Unit]# at -M -f test10.sh now
job 8 at Fri Aug 21 16:47:00 2020
[root@tzPC 16Unit]# atq
5    Sat Aug 22 16:00:00 2020 a root
6    Sat Aug 22 16:47:00 2020 a root
7    Sat Aug 22 13:30:00 2020 a root
8    Fri Aug 21 16:47:00 2020 = root

删除等待中的作业

artm 7

cron命令定期执行脚本

使用cron命令,前提条件是系统是7X24小时运行,如果计划运行时间系统正好处于关机状态,这个计划任务就不会运行,即使开机也不会运行错过的计划任务。

启动crond服务并加入开机启动项

[root@tzPC 16Unit]# systemctl start crond
[root@tzPC 16Unit]# systemctl enable crond

cron时间定义格式

min hour dayofmonth month dayofweek command

dayofmonth表示月份中的日期值(1-31日)

每天10:15运行命令

15 10 * * * command

每周一下午4:15运行命令

15 16 * * 1 command

在每月最后一天执行命令(这里书中命令有误),应该如下写法

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

命令列表必须指定脚本绝对路径,同时也可给脚本参数或者重定向到文件

15 10 * * * /home/tz/test4.sh > test4out

-e参数创建cron计划任务

[root@tzPC 16Unit]# crontab -e

15 10 * * * /root/script/16Unit/test10.sh >test10out

查看cron时间表

[root@tzPC 16Unit]# crontab -l
15 10 * * * /root/script/16Unit/test10.sh >test10out

浏览cron目录

有4个基本目录

hourly、daily、monthly、weekly

分别对应每小时、每天、每月、每周运行一次

将脚本放入对应目录即可

[root@tzPC etc]# ls /etc/cron.*ly
/etc/cron.daily:
logrotate  man-db.cron

/etc/cron.hourly:
0anacron

/etc/cron.monthly:

/etc/cron.weekly:

anacron命令

此命令执行的计划任务如果错过了执行时间,会尽快运行错过的计划任务。

常用于清理日志文件

该命令只会处理位于cron目录的脚本

用时间戳来确定脚本是否在规定时间内运行,每个cron目录都有个时间戳文件,位于/var/spool/anacron

[root@tzPC etc]# cat /var/spool/anacron/cron.monthly
20200817

查看anacron时间表

[root@tzPC etc]# cat /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

anacron时间定义格式

period delay identifier command

 #待补充

 学习来自:《Linux命令行与Shell脚本大全 第3版》第16章

今天的学习是为了以后的工作更加的轻松!
原文地址:https://www.cnblogs.com/tz90/p/13533942.html