Linux的脚本运行是在外面赋予执行权限,然后再进行运行的。但是这并不是唯一一种的运行方式。本章介绍控制shell脚本再系统的运行方式以及运行时间的不同方法。
1、处理信号
Linux进程之间的通讯使用的就是信号。这些信号包括停止、启动和终止进程。也可以通过信号控制脚本运行。
1.1、信号回顾
Linux和应用程序可以生成30多个Linux信号,常见信号如下:
默认情况下,脚本葫芦收到的任何SIGOUIT(3)和SIGTERM(15)信号。但是会处理任何SIGHUP(1)和SIGINT(2)信号。
bash shell收到SIGHUP(1)会退出。收到SIGNINT信号,shell立即终端。
1.2、生成信号
1、终断进程
使用 ctrl+c 生成SIGINIT信号。
sleep 100
2、暂停进程
ctrl + z 生成STGSTP信号。停止进程,进程保留在内存中,能够从停止的地方继续执行;
使用 ctrl + z 组合键如下:
其中[1],1代表作业(job),shell脚本以作为为单位在进程中运行,每个作业都有自己的作业编号;
此时,通过exit 退出shell的时候,就会提示:There are stopped jobs.
通过ps查看作业状态:
其中 STAT 中 T 表示作业状态,表示该作业正在被跟踪或者已经停止;再次输入exit就可以停止作业;
同时,也可以发送信号9 SIGKILL信号来终止作业;
kill -9 20605
这样就直接终止了PID为20605的进程
1.3、捕获信号
trap命令可以指定能够通过shell脚本监控和拦截的Linux信号。如果脚本收到trap命中列出的信号,它将保护盖信号不被shell处理,并在本地处理它。
trap使用格式:trap commands signals
#!/bin/bash # testing output in a background job trap "echo Haha" SIGINT SIGTERM echo "This is a test program" count=1 while [ $count -le 10 ] do echo "Loop #$count" sleep count=$[ $count + 1 ] done echo "This is the end of the test program"
每次使用 ctrl+c 组合监视,脚本执行在trap命令中指定的echo语句,而不是忽略信号并容许shell停止脚本。
1.4、捕获脚本退出
shell脚本退出的时候也可以捕获信号。只需要向trap命令添加EXIT信号;
#!/bin/bash # trapping the script exit trap "echo byebye" EXIT count=1 while [ $count -le 5 ] do echo "Loop #$count" sleep 3 count=$[ $count + 1 ] done
使用ctrl+c组合键发送SIGINT信号,脚本将退出,但是在脚本退出之前,shell将执行trap命令;
1.5、移除捕获
要移除捕获,使用破折号作为命令和想要恢复正常行为的信号列表。
#!/bin/bash # removing a set trap trap "echo byebye" EXIT count=1 while [ $count -le 5 ] do echo "Loop #$count" sleep 3 count=$[ $count + 1 ] done trap - EXIT echo "I just remved the trap"
脚本正常运行结束,这忽略EXIT信号,但是如果中途ctrl+c终止信号,则已让裕兴EXIT信号;
2、以后台模式运行脚本
我们的进程可以运行在后台,而后台运行进程与STDIN、STDOUT以及STDERR无关;
以下我们要介绍如何在Linux系统中以后台模式运行脚本。
2.1、以后台模式运行
在命令后加上一个 & 符号,就将进程运行到后端了
./test1 &
[1] 19582 #显示作业号 和进程号
脚本输出结果,会与单前运行的命令结果混合在一起,等脚本再后台执行完成以后,会有有提示:
[1]+ Done ./test
表示后台进程运行完成;
2.2、运行多个后台作业
./test1 & ./test1 & ./test1 &
可以通过ps命令查看
2.3、退出终端
每个后台进程都关联一个终端会话(pts/0)终端,退出终端会话,就会腿很粗后台运行的进程;
一般情况下,我们更加希望关闭控制台,但是后台进程继续运行,如何实现呢?
3、不适用控制台的情况下运行脚本
有时需要从终端会话启动shell脚本,然后让脚本再结束之前以后台模式运行,即使退出终端会话也是如此。可以使用nohup命令实现;
nohup命令运行另一个命令阻塞发送到进程的任何SIGHUP信号。这可以防止在退出终端会话时退出进程。
$nohup ./test1 & [1] 19831 $nohup: appending output to 'nohup.out'
#nohup命令将脚本胡烈任何终端会话发送的SIGHUB信号。因为nohup命令将进程和终端断开,所以进程没有STDOUT和STDERR输出连接。为了接受命令生成的任何输出,nohup命令自动将STDOOUT和STDERR消息重定向到称为nohup.out的文件
cat nohup.out
4、作业控制
重启、停止、终止、恢复作业操作叫做作业控制(job control)。使用作业控制可以完全控制进程在shell环境中的运行方式。
4.1、查看作业
#!/bin/bash # testing job control echo "This is a test program $$" # $$ 变量显示Linux系统分配给脚本的PID count=1 while [ $count -le 10 ] do ehco "Loop #$count" sleep 10 count=$[ $count + 1 ] done echo "This is the end of the test program"
./test4
./test4 > test4out &
jobs #通过jobs命令查看后台运行停止的进程
jobs命令参数:
在jobs显示的内容中:+ 代表默认作业,- 代表当前默认作业结束后将成为默认作业的作业;
4.2、重新启动停止作业
bg 命令,提供后台模式中重新启动作业的功能;
$ bg 2 [2]+ ./test4 & Loop #2 $ Loop #3 Loop #4 $ jobs
fg 命令,听前台模式下作业重新启动的功能;
$ jobs [1]+ Stopped ./test4 $ fg 1 ./test4
5、变得更好
默认情况下,shell在CPU上运行的调度优先级(scheduling priority)都相同。调度优先级是内核相对其他进程分配给某一进程CPU时间量。
调度优先级从-20(最高)到+20(最低)。默认请看下bash shell启动所有优先级为0的进程。
而 nice 命令则是用来更改进程优先级的。
5.1、nice命令
nice -n 选定新的优先级水平:
$ nice -n 10 ./test4 > test4out & [1] 29476
增加进程优先级:
$ nice -n -10 ./test4 > test4out & [1] 29501 $ nice: cannot set priority: Permission denied #报错,nice不容许普通用户增加命令优先级 [1]+ Exit 1 nice -n -10 ./test4 > test4out
5.2、renice命令
更改已经在系统中运行的命令优先级。这就需要使用人ice命令。
$./test4 > test4out & [1] 29504 $ ps al $ renice 10 -p 29504 $ ps al
renice的限制:
1、只能对拥有进程使用renice命令;2、只能使用renice命令将进程调至更低的优先级;3、根用户可以使用renice命令将任何进程调至任何优先级;
6、准确无误的运行
指定脚本的预运行时间:1、at命令;2、batch命令;3、cron表格;
6.1、使用at命令调度作业
at提交到一个队列,在后台运行使用atd命令来完成;
atd命令实际上是检查/var/spool/at文件,默认60s检查一次。如果有作业,且与运行时间匹配,则执行;
1、at命令格式
at [ -f filename ] time
time格式:10:15(标准时间) AM/PM提示符比如 10:15PM 具体时间:now、noon、midnight、teatime(4PM)
time的日期格式:MMDDYY、MM/DD/YY或者DD.MM.YY 文本日期格式:Jul 4或者Dec 25 没有年份也可以 时间增量:Now + 25 minutes 或者 10:15 + 7 days
at命令会将作业提交到作业列表中等待执行。也可以使用 -q 参数有限执行该作业
2、获取作业输出
将捕获到的作业输出,作为电子邮件发送出来
#!/bin/bash # testing the at command time=`date +%T` echo "This script ran at $time" echo "This is the end of the script" >&2
at -f test5 12:08
>N 1 rich@testbox Sat Nov 3 12:08 14/474 "Output from your job
3、列出排队的作业
atq 命令能够查看那些作业在排队
at -f test5 10:15 at -f test5 2007-11-04 10:15 at -f test5 4PM at -f test5 1PM tomorrow atq
4、移除作业
atrm 命令移除作业
atrm 8 #指定作业号即可 atq
6.2、使用batch命令
这个命令是安排脚本再系统使用率低时运行。如果系统处于高负载,batch的作业则会推迟提交。知道系统负载降低;
batch [ -f filename ] [ time ]
6.3、调度定期脚本
crontab 调度列表,定期执行脚本程序。
1、cron表格
格式如下:
min hour dayofmonth month dayofweek command
dayofweek:mon tue wed thu fri sat sun
dayofmonth:1-31
month:1-12
例如:15 10 * * * command #10:15
例如:15 16 * * 1 command #每周一的16:15
例如:00 12 1 * * command #每月的1号,中午12点
2、构建cron表格
crontab -l #查看表格内容
3、anacron程序
如果使用cron调度作业运行是Linux系统处于关闭状态,则作业将无法运行。cron程序无法在系统打开后重新运行错过的作业。为了解决这个问题,许多Linux发行版本提供了anacron程序。
anacron在系统应为关机后没有执行既定的脚本的话,在系统恢复以后,会补上;
anacron的程序使用给自己的表格,位于/etc/anacrontab中;
anacron表格格式:
period delay identifier command
period:定义作业应该间隔多久运行一次
delay:指定在anacron程序确定应该运行一个命令之后需要多久才会实际运行该命令;
identifier:为一个非空字符串,可以唯一表示日志消息和错误电子邮件中的作业。
7、从头开始
让脚本再Linux系统已启动或者用户启动新的bash shell会话时并自动运行。
作为系统管理员,在系统启动的时候有些操作,在启动系统的时候就需要执行以下,比如:重置自定义日志文件或者启动自定义应用程序等。
7.1、在启动时启动脚本
在将shell脚本设置为启动时自动启动之前,需要了解下Linux启动过程的工作方式。Linux在启动时按照一定的顺序启动脚本,了解该过程将有助于您让脚本按照预期的方式运行。
1、启动过程
Linux系统的第一启动程序 init 程序 /sbin/init 它的进程为PID 1;
init程序读取 /etc/inittab 文件。根据不同级别来启动程序;Linux启系统的运行级别:
Linux常见的运行级别是5。然后就是运行级别为3。
Linux系统通过rc脚本确定以哪种运行级别启动那些程序。启动脚本是启动应用程序的shell脚本,为运行的程序提供必要的环境的脚本。
系统脚本程序放在/etc/rc.d目录中;
2、定义脚本
最好不要弄乱Linux发型版中的任何启动脚本文件。发行版Linux系统提供了一些工具自动在添加服务器应用程序时构建这些脚本,手动更改这些脚本可能会出现问题。而有一个脚本程序就是用来给用户指定启动系统时需要运行的程序的:
7.2、随新shell一起启动
每个用户都包含两个主目录文件:
1、.bash_profile文件
2、.bashrc文件
新用户登录、在运行新的shell的时候,就会执行.bash_profile文件。该文件中放置任何您希望登录时运行的脚本。
每次启动新的shell时(包括新用户登录时)运行.bashrc文件。可以向主目录的.bashrc文件添加一个简单的echo语句,然后启动一个新shell以测试该特性:
$ bash
This is a new shell!!
如果是希望每个用户都运行这个脚本,则将脚本程序卸载/etc/bashrc文件中;