zoukankan      html  css  js  c++  java
  • bash shell笔记6 脚本控制

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。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以外终止。但是bash shell接收任何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   RSS TTY      STAT START   TIME COMMAND
    root      5007  0.0  0.0   4812   496 pts/0      16:19   0:00 sleep 100
    root      5009  0.0  0.0   4812   496 pts/0      16:19   0:00 sleep 200
    root      5025  0.0  0.1   5356   944 pts/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命令下回显echo you 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
    运行一半的程序被暂停后,通过fg 1又可以调到命令行运行下去了。

    5、使脚本更好的运行
    linux是一个多任务操作系统,内核负责为系统中运行的每个进程分配CPU时间。而CUP中一次就能运行一个进程,因此内核轮流向每个进程分配CPU时间。从shell启动的所有进程在linux系统上的调度优先级都是相同的。调度优先级是内核相对其他进程分配某一个进程的CPU时间量。
    调度优先级是一个整数值,从-20(最高优先级)到+20(最低优先级),默认情况下,bash shell启动所有优先级为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]+  Exit 1                  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
    通过这种方法就可以判定每个月最后一天啦~(≧▽≦)/~

     


  • 相关阅读:
    navicat 创建查询失败 can not create file
    使用Themeleaf时, HTML内嵌的JS代码需要注意< 和 >的问题
    window下查杀占用端口的进程
    Spring MVC的Rest URL 被错误解析成jsp, 导致404错误(XML方式下@Controller和@RestController需要配置<mvc:annotation-driving/>)
    一个本地DNS解析和mysql授权导致的Mysq连接失败问题(Access denied for user 'loan'@'kfcsdb1' (using password: YES))
    taglib报错The content of element type "taglib" must match "(tlib-version,...)
    cvc-complex-type.2.4.a: Invalid content was found starting with element 'display-name'
    在eclipse中运行spring web application时的异常: java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
    Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况
    如何在Spring MVC Test中避免”Circular view path” 异常
  • 原文地址:https://www.cnblogs.com/songfeixiang/p/3733757.html
Copyright © 2011-2022 走看看