bash shell笔记6 脚本控制

来源:互联网 发布:做笔记的软件 编辑:程序博客网 时间:2024/06/18 03:51
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://twentyfour.blog.51cto.com/945260/522415

知识体系:
#回顾信号功能
#隐藏在背景中
#在没有控制台的情况下运行
#做得更好
#准确无误的运行
#从头开始
前面运行脚本的方式都是在命令行界面运行,实际上还有运行shell脚本的其他方式,以及中断脚本的运行进程,控制脚本的运行时间都可以实现。

1、处理信号
linux下有各种信号,如停止、启动、终止。通过信号控制shell脚本的运行只需要使得shell脚本接收来自linux体系特定信号时执行命令即可。
1.1、linux信号回顾
系统和应用程序可以生产30多个linux信号,如下罗列出常用的linux系统信号:
******************************************************
 信号          值               描述
           SIGHUP          挂起进程              
           SIGINT          中断进程           
           SIGQUIT         停止进程            
           SIGKILL         无条件终止进程         
 15          SIGTERM         如果可能的话终止进程         
 17          SIGSTOP         无条件停止,但不终止进程  
 18          SIGTSTP         停止或暂停进程,但不终止       
 19          SIGCONT         重新启动停止的进程
*******************************************************
默认情况下,bash shell忽略接收到的任何SIGQUIT和SIGTERM信号,以防止交互的shell以外终止。但是bashshell接收任何SIGHUP和SIGINT信号。
1.2、生成信号
1》中断进程
使用ctrl+c组合键可以生产SIGINT信号,比如用sleep命令测试:
[root@wzp~]# sleep 100
如果我不使用组合键,那么控制台就无法进行输入了,一直运行该sleep程序,所以通过这方法可以终止进程。
2》暂停进程
有些进程想暂停而不是终止它,可以使用ctrl+z组合键生产SIGTSTP信号
[root@wzp~]# sleep 100

[1]+ Stopped                sleep 100
看到没有,如果是暂停进程,会有log信息显示stopped的。
如上可以看到中括号里面有一个1数值,这个就是shell分配的作业编号,第一个启动的进程分配作业编号1,第二个启动的进程分配作业编号2,依此类推,如果shell会话中存在停止的作业,退出shell会发出警号的:
[root@wzp ~]# exit
exit
There are stopped jobs.
[root@wzp ~]# exit
退出时说存在着被暂停的作业,不过你再次输入exit可以终止了进程强行退出shell,或者说你可以通过Kill命令发出SIGKILL命令终止它:
[root@wzp~]# sleep 100

[1]+ Stopped                sleep 100
[root@wzp ~]# sleep 200

[2]+ Stopped                sleep 200
[root@wzp ~]# ps au
USER      PID %CPU %MEM   VSZ   RSSTTY     STAT START   TIMECOMMAND
root     5007  0.0 0.0  4812   496pts/0     16:19   0:00 sleep 100
root     5009  0.0 0.0  4812   496pts/0     16:19   0:00 sleep 200
root     5025  0.0 0.1  5356   944pts/0   R+  16:19   0:00 ps au
[root@wzp ~]# exit
exit
There are stopped jobs.
[root@wzp ~]# kill -9 5007
[root@wzp ~]# kill -9 5009
[1]- 已杀死              sleep 100
[2]+ 已杀死              sleep 200
这样子通过kill进程号达到终止了进程。
1.3、捕获信号
trap命令可以指定通过shell脚本监控和拦截信号,使得信号不被shell处理,而在本地处理它,其格式为:
trap commands signals
下面看个例子,使用trap命令来忽略SIGINT和SIGTERM信号的简单示例:
[root@wzp ~]# chmod u+x 6.1test 
[root@wzp ~]# cat 6.1test 
#!/bin/bash
trap "echo you can not stop me!" SIGINT SIGTERM
echo "this is a test program"
count=1
while [ $count -le 10 ]
do
  echo "loop #$count"
  sleep 3
  count=$[ $count + 1 ]
done
echo "the program is over"
[root@wzp ~]# ./6.1test 
this is a test program
loop #1
loop #2
loop #3
you can not stop me!
loop #4
loop #5
loop #6
you can not stop me!
loop #7
loop #8
you can not stop me!
loop #9
loop #10
the program is over
当如上程序每隔3秒显示一次信息的时候,我通过ctrl+c暂停程序的时候,该信号都被忽略了,并且在trap命令下回显echoyou can not stop me!内容,并且程序一直执行完毕。由此可以trap命令的强大哈!
1.4、捕获脚本退出
除了上面在shell脚本中捕获信号之外,还可以在shell脚本退出那瞬间捕获,只需要在trap命令后添加EXIT信号,看下例子:
[root@wzp~]# cat 6.1test 
#!/bin/bash
trap "echo yeah, the program is over" EXIT
count=1
while [ $count -le 5 ]
do
  echo "loop #$count"
  sleep 3
  count=$[ $count + 1 ]
done
[root@wzp ~]# ./6.1test 
loop #1
loop #2
loop #3
loop #4
loop #5
yeah, the program is over
当脚本准备退出之际,就会触发trap,并且捕获了EXIT信号显示echo内容
当然,如果你ctrl+c终止进程也是会捕获EXIT信号的,暂停进程则不会。
1.5、移除捕获
我们可以使用破折号来移除捕获,使得shell捕获信号的功能失效,例子:
[root@wzp~]# cat 6.1test 
#!/bin/bash
trap "echo yeah, the program is over" EXIT
count=1
while [ $count -le 5 ]
do
  echo "loop #$count"
  sleep 3
  count=$[ $count + 1 ]
done
trap - EXIT
[root@wzp ~]# ./6.1test 
loop #1
loop #2
loop #3
loop #4
loop #5
我只是在上面的例子中最后添加了移除捕获的一行,结果脚本退出的捕获被移除了,就没有了捕获信息显示了。

2、以后台模式运行脚本
有些shell脚本在执行中需要等待漫长时间,而且终端回话无法执行其他操作,这个时候就可以使得shell放置到后台运行。
2.1、以后台模式运行
这个很简单就得意实现,只要在运行脚本时在命令后面附带一个&符号即可。
[root@wzp~]# cat 6.2test 
#!/bin/bash
count=1
while [ $count -le 5 ]
do
  echo "loop #$count"
  sleep 3
  count=$[ $count + 1 ]
done
[root@wzp ~]# ./6.2test &
[5] 7348
[root@wzp ~]# loop #1
loop #2
loop #3
loop #4
loop #5

[5]  Done                   ./6.2test
通过这方法就可以到程序放到后台运行,控制台便可以进行其他操作。
所以可以借用这种方法运行多个程序。

3、在不使用控制台的情况下运行脚本
一个程序运行过程默认情况下会随着中断回话的退出而中断。这个时候就可以借用nohup命令来使得阻塞任何发送到进程的SIGHUP信号。
[root@wzp~]# cat 6.2test 
#!/bin/bash
count=1
while [ $count -le 5 ]
do
  echo "loop #$count"
  sleep 3
  count=$[ $count + 1 ]
done
[root@wzp ~]# nohup ./6.2test &
[2] 7877
[root@wzp ~]# nohup: appending output to“nohup.out”

[root@wzp ~]# 
[2]- Done                   nohup ./6.2test
因为nohup将进程和终端断开,所以进程没有STDOUT和STDERR输出链接。nohup命令将自动把这两类消息重定向到nohup.out这个自动新创建的文件中去:
[root@wzp ~]# cat nohup.out 
loop #1
loop #2
loop #3
loop #4
loop #5
这个文件的内容跟命令行运行进程输出是完全一样的!

4、作业控制
shell运行的进程可以通过ctrl+z中断,利用kill终止进程,可以使用发送SIGCONT信号重启停止的进程。对于重启、停止。终止、恢复作业的操作就叫做作业控制。
4.1、查看作业
通过jobs命令可以直接查看shell处理的当前作业,看例子:
[root@wzp~]# nohup ./6.2test &
[1] 8477
[root@wzp ~]# nohup: appending output to“nohup.out”

[root@wzp ~]# nohup ./6.2test &
[2] 8479
[root@wzp ~]# nohup: appending output to“nohup.out”

[root@wzp ~]# jobs 
[1]- Running                nohup ./6.2test &
[2]+ Running                nohup ./6.2test &
[root@wzp ~]# jobs
[1]- Done                   nohup ./6.2test
[2]+ Done                   nohup ./6.2test
我运行两次同样的脚步程序到后台,然后通过jobs查看,显示running状态,等到脚步运行结束再次jobs查看即可显示已完成状态。
[root@wzp~]# nohup ./6.2test &
[2] 8594
[root@wzp ~]# nohup: appending output to“nohup.out”

[root@wzp ~]# jobs
[2]+ Running                nohup ./6.2test &
[root@wzp ~]# kill 8594
[root@wzp ~]# jobs
[2]+ 已终止              nohup ./6.2test
当脚本一开始运行到后台会显示了PID号8594,当脚本还没运行结束我kill掉进程,也可以通过jobs查看出进程已经被kill了。
4.2、重新启动停止的作业
我们可以通过ctrl+z暂停进程,当要重新启动停止的作业时可以通过使用带有作业编号的bg命令,看例子:
[root@wzp~]# nohup ./6.2test 
nohup: appending output to “nohup.out”

[1]+ Stopped                nohup ./6.2test
[root@wzp ~]# jobs 
[1]+ Stopped                nohup ./6.2test
[root@wzp ~]# bg 1
[1]+ nohup ./6.2test &
[root@wzp ~]# jobs 
[1]+ Running                nohup ./6.2test &
[root@wzp ~]# jobs 
[1]+ Done                   nohup ./6.2test
先是把程序放到后台运行,然后马上暂停了进程运行,通过jobs即可查看。然后通过bg命令附带作业编号1重启进程。注意:作业编号在我一开始暂停进程的时候就显示了[1]。
上面的bg命令重启的进程后是放到进程去运行的。如果你想把它放到显示屏运行,即可以使用带编号的fg命令,看例子:
[root@wzp~]# ./6.2test 
loop #1
loop #2

[1]+ Stopped                ./6.2test 
[root@wzp ~]# fg 1
./6.2test
loop #3
loop #4
loop #5
运行一半的程序被暂停后,通过fg1又可以调到命令行运行下去了。

5、使脚本更好的运行
linux是一个多任务操作系统,内核负责为系统中运行的每个进程分配CPU时间。而CUP中一次就能运行一个进程,因此内核轮流向每个进程分配CPU时间。从shell启动的所有进程在linux系统上的调度优先级都是相同的。调度优先级是内核相对其他进程分配某一个进程的CPU时间量。
调度优先级是一个整数值,从-20(最高优先级)到+20(最低优先级),默认情况下,bashshell启动所有优先级为0的进程
5.1 nice命令
nice命令可以在启动命令时设置它的调度优先级,要让命令在更低的优先级下运行,可以使用-n选项。看个例子:
[root@wzp ~]# nice -n 10 ./6.2test &
[1] 9888
这样子,该程序就运行在10优先级下了。还有一点注意的是我是通过root超级用户设定脚本运行的优先级别,如果设置在更低的优先级,对于普通用户即可操作,并且一般是属于该脚本程序的用户所有者。但是普通用户无法设置脚本再更高的优先级别下运行。看例子:
[testuser@wzp~]$ ll
总计 8
-rwxr--r-- 1 testuser root 107 02-15 20:00 6.2test
[testuser@wzp ~]$ nice -n 10 ./6.2test &
[1] 10164
[testuser@wzp ~]$ 
loop #1
loop #2
loop #3
运行指定在低优先级是没问题的!
[testuser@wzp~]$ nice -n -10 ./6.2test &
[1] 10186
[testuser@wzp ~]$ nice: cannot set niceness: 权限不够

[1]+  Exit1                 nice -n -10 ./6.2test
设定在高优先级下运行报权限不够的错误信息!
5.2、renice命令
有使用需要更改系统中已运行的优先级,就可以使用renice命令,例子:
[root@wzp~]# nohup ./6.2test &
[1] 10369
[root@wzp ~]# nohup: appending output to“nohup.out”

[root@wzp ~]# renice -10 -p 10369
10369: old priority 0, new priority -10
原先我设定脚本再后台运行,并且默认是0的优先级别。通过renice命令指定-10更高的优先级别,并且通过-p加PID号设定,从log信息我们知道旧的调度优先级被修改了。

6、准确无误的运行
shell脚本有时候需要设定在给定的时间运行,特别是半夜,等业务量没有那么忙的时候往往是SA反而忙碌的时候,我们很容易可以想到通过计划任务是实现这一需求,这里头主要有三种方式:
*at 命令
*batch 命令
*cron 表格
6.1、使用at命令调度作业
对于at命令的具体使用方面这里就不罗嗦了,可以看下网上的资料或者linux的复习进阶一讲述。其命令格式、日期格式都是需要注意的。
这里讲述下通过运行atd和sendmail应用程序来获取作业输出:
由于linux使用提交作业的用户的电子邮箱地址作为STDOUT和STDERR,所以任何以STDOUT和STDERR为目的地的输出都通过电子邮件发送给用户。
当需要制定运行某个文件的at计划,可以附带-f选项,如:
at -f testfile xx:xx
当制定好at命令后可以通过atq命令查看计划列表;
如果要删除已经制定好的计划列表可以通过atrm命令,附带计划number。
6.2、使用batch命令
batch命令跟at命令不太相同,我们知道at命令是在一个指定的时间运行计划好的命令,而batch则是安排脚本在系统使用率低的时候运行。如果linux处于高负荷下运行,那么batch命令就会延迟提交作业的运行。跟at命令类型的地方是命令的格式,可以通过-f参数从文件中读取,默认从STDIN读取。
6.3、调度定期脚本
如果需要脚本在每天、每周、每月的一个特定时间执行脚本,就可以使用cron程序调度需要运行的作业。cron程序在后台运行,它从特殊表格中查找需要调度运行的作业。
对于cron表格的一些命令格式、时间格式,构建cron表格等内容就不说了,这个直接去找网上资料或者看linux复习进结一的计划任务即可。
不过有点挺搞的提及下:系统管理员想在每个月的最后一天执行脚本,那么cron表格应该怎么写么?我们知道每个月的最后一天有可能是28、29、30、31,那么应该怎么判断这一天呢?答案:
这里可以借助添加if-then语句,用date命令检查明天是否1号即可解决问题,具体的cron表格内容如下:
* * * * * if [ `date +%d -d tomorrow` = 01 ]; then ;command
通过这种方法就可以判定每个月最后一天啦~\(≧▽≦)/~

 


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 数学计算总出错怎么办 16岁不认字怎么办 数学细节丢分怎么办 感觉自己老了怎么办 小学拼音不过关怎么办 小学面试不过关怎么办 小学阅读不过关怎么办 孩子计算老出错怎么办 工作中总是马虎怎么办 孩子总是计算错误怎么办 做设计老是犯错怎么办 小学生阅读总出错怎么办 写作文没思路怎么办 孩子不爱写作文怎么办 写作文没有素材怎么办 写作文没有灵感怎么办 做事工作马虎粗心大意怎么办 小孩作业马虎粗心大意怎么办 孩子写字一直错怎么办 孩子写字老错怎么办 写错字涂黑了怎么办 写错字不能涂改怎么办 孩子爱写错别字怎么办 孩子读题马虎怎么办 孩子知错不该怎么办 小孩胆小反应慢怎么办 孩孑经常流鼻血怎么办 中考考号写错了怎么办 头后仰就头晕怎么办 感觉自己要晕倒怎么办 孩子不愿动手写字怎么办 老年人恶心想吐怎么办 小学生老写错别字怎么办 突然头晕站不稳 怎么办 早上起床突然天旋地转怎么办 躺着突然感觉天旋地转怎么办 眩晕症发作时怎么办 低血糖恶心想吐怎么办 更年期头晕头胀怎么办 年轻人头晕头胀怎么办 教案:《眯眼了怎么办》