脚本控制 #
脚本控制一般分为两种:
- 脚本的优先级控制
- 通过信号控制
脚本优先级控制 #
nice
和renice
可以调整脚本的优先级,调整资源的占用,如 CPU。- 避免不可控的死循环
- 死循环会导致 CPU 占用过高
- 死循环会导致死机,创建大量的子进程,叫做 fock 炸弹。如
.(){.|.&};.
,可以当做func(){func|func &}; func
。
ulimit -a
可以查看当前的终端的系统限制:
[root@pooky ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 63408
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 63408 # 用户的最大进程数
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
当 fock 炸弹创建大量的进程,超过 max user processes 的限制时,系统就会停止响应,因为 CPU 在不停的创建子进程。
捕获信号 #
kill
默认发送 15 号信号给进程。ctrl + c
发送 2 号信号。- 9 号信号不可阻塞,
trap
是无法捕获的。
有些应用程序,不希望被 ctrl + c
或者 kill
的信号中断,就可以使用 trap
捕获信号,来屏蔽掉这些信号。
#!/bin/bash
trap "echo sig 15" 15
trap "echo sig 2" 2 # 捕获了 ctrl + c 的信号
echo $$
while :
do
:
done
计划任务 #
一次性计划任务 #
at [OPTIONS] <系统时间>
命令:
[root@pooky tmp]# date
Thu Sep 10 21:21:13 CST 2020
[root@pooky tmp]# at 21:23
at> echo hello > /tmp/hello.txt
at> <EOT>
job 2 at Thu Sep 10 21:23:00 2020
[root@pooky tmp]# atq
2 Thu Sep 10 21:23:00 2020 a root
[root@pooky tmp]# cat /tmp/hello.txt
hello
[root@pooky tmp]# ls -l /tmp/hello.txt
-rw-r--r--. 1 root root 6 Sep 10 21:23 /tmp/hello.txt
at
命令执行计划任务之后,可以使用 ctrl + d
退出。
atq
命令可以查看还没有执行的一次性计划任务。
选项:
-m
:当a
t 的工作完成后,即使没有输出讯息,亦以 email 通知使用者该工作已完成。-l
:at -l
相当于atq
,列出目前系统上面的所有该使用者的at
job。-d
:at -d
相当于atrm
,可以取消一个在at
job;-v
:可以使用较明显的时间格式列出at
job;-c
:可以列出后面接的该项工作的实际指令内容。
周期性计划任务 #
Linux 默认安装 crontab
,用来执行周期性任务。crond
进程会定期检查是否有要执行的任务,如果有,则自动执行。
crontab [OPTIONS] [CMD]
命令,配置计划任务的格式,如 0 1 * * * root /user/local/run.sh
,每个段分别表示:
minute hour day month week command
minute
: 分钟,从0
到59
之间的任何整数。hour
:小时,从0
到23
之间的任何整数。day
:日期,从1
到31
之间的任何整数。month
:月份,从1
到12
之间的任何整数。week
: 星期几,从0
到7
之间的任何整数,0
或7
代表星期日。command
: 行的命令,可以是系统命令,也可以是脚本文件。要注意命令的路径,如果没有配置 PATH,需要写绝对路径。
各段中还可以使用下面的字符:
*
:代表所有可能的值,例如month
字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。,
:可以用逗号隔开的值指定一个列表范围,例如,1,2,5,7,8
-
:可以用整数之间的中杠表示一个整数范围,如1-5
表示1,2,3,4,5
/
:可以用正斜线指定时间的间隔频率,例如0-23/2
表示每两小时执行一次。同时正斜线可以和星号一起使用,如*/10
,如果用在minute
字段, 表示每十分钟执行一次。
选项:
-e
:设置用户的计划任务-l
:列出用户的计划任务-r
:删除用户的计划任务-u
:指定用户名,如果不指定,默认是当前用户。
/var/spool/cron/
会有一个与用户同名的文件。
可以使用命令添加计划任务,也可以修改 /etc/crontab
配置文件:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
示例 #
* * * * * command
每分钟执行一次 command
。
10,20 * * * * command
每小时的第 10
和第 20
分钟执行一次。
10,20 8-11 */2 * * command
每隔两天的上午 8
点到 11
点的第 10
和第 20
分钟执行。
10 1 * * 6,0 /etc/init.d/smb restart
每周六、周日的一点十分重启 smb
日志 #
计划任务的日志可以查看 /var/log/cron
文件:
[root@pooky ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@pooky ~]# tail -f /var/log/cron
Sep 10 21:01:02 pooky run-parts(/etc/cron.hourly)[15528]: starting mcelog.cron
Sep 10 21:01:02 pooky run-parts(/etc/cron.hourly)[15546]: finished mcelog.cron
Sep 10 21:10:01 pooky CROND[16058]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Sep 10 21:20:01 pooky CROND[16707]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Sep 10 21:30:01 pooky CROND[17353]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Sep 10 21:40:01 pooky CROND[17936]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Sep 10 21:53:18 pooky crontab[18695]: (root) REPLACE (root) # 表示编辑了一个 job
Sep 10 21:53:18 pooky crontab[18695]: (root) END EDIT (root) # 表示完成了编辑
Sep 10 21:54:02 pooky CROND[18769]: (root) CMD (ntpdate ntp.swinfra.net)
上面的示例设置了周期任务 */2 * * * * ntpdate ntp.swinfra.net
每两分钟同步一次时间。
延时计划任务 #
在有些意外情况下,周期计划任务可能没有执行,比如机器意外关机了。这时候就需要延时计划任务,可以在开机之后再延后运行。
/etc/cron.d/0hourly
:
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly # 每一个小时的第一分钟 运行 run-parts /etc/cron.hourly
run-parts
在调用 /etc/cron.hourly
之后会在某处记录一个标记,表示这一个小时已经运行过。再下次开机时会检查这个标记,如果这个小时已经运行过,就不会再运行。
cron.hourly
对应的是每小时的延时任务,其他的任务在 /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 # 随机在 0 到 45 之间选择延时时间
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22 # 延时任务在 3 到 22 点之间运行
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily # 延时 5 分钟,就是每天的 3:05 分开始执行延时任务
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
任务锁 #
在运行一个周期任务时,如果该任务执行时间较长,导致下一个周期开始,这样再执行任务就可能冲突。这时候可以使用任务锁来避免这种问题。
flock -x
来运行,会加上一个排它锁:
[root@pooky ~]# flock -xn "/tmp/f.lock" -c "/root/test.sh"
“/tmp/f.lock” 就是锁文件。
选项:
-s
获得一个共享锁-x
获得一个独占锁,这是默认的-u
删除一个锁,通常是不需要的,因为在文件关闭时锁会自动删除-n
如果没有获得锁,直接失败而不是等待-w
如果没有获得锁,等待指定时间-o
在执行命令之前关闭保持锁的文件描述符-c
运行一个命令