zoukankan      html  css  js  c++  java
  • shell脚本控制

    知识体系:
    #回顾信号功能
    #隐藏在背景中
    #在没有控制台的情况下运行
    #做得更好
    #准确无误的运行
    #从头开始
    前面运行脚本的方式都是在命令行界面运行,实际上还有运行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
    通过这种方法就可以判定每个月最后一天啦~\(≧▽≦)/~


  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/liuzhuqing/p/7480847.html
Copyright © 2011-2022 走看看