1

时间:2017年09月26日星期二
说明:本文部分内容均摘取自书籍《Linux命令行与shell脚本编程大全》,版权归原作者所有。《Linux命令行与shell脚本编程大全》(第三版)第十六章学习总结

第十六章:控制脚本

本章内容

处理信号
以后台模式运行脚本
禁止挂起
作业控制
修改脚本优先级
脚本执行自动化

16.1 处理信号

16.1.1 重温Linux信号

Linux系统信号

Linux利用信号与运行在系统中的进程进行通信
可以使用信号来停止/启动/终止进程
可以通过对脚本进行编程,使其在收到特定信号时执行某些命令,从而控制shell脚本
默认情况下,bash shell会忽略收到的任何3和15信号
但是bash shell会处理1和2信号

常见的Linux系统信号

信号:值:描述
1:SIGHUP:挂起进程
2:SIGINT:终止进程
3:SIGQUIT:停止进程
9:SIGKILL:无条件终止进程
15:SIGTERM:尽可能终止进程
17:SIGSTOP:无条件停止进程,但不是终止进程
18:SIGTSTP:停止或暂停进程,但不终止进程
19:SIGCONT:继续运行停止的进程

16.1.2 生成信号

1.中断进程

使用Ctrl+C组合键会生成2(SIGINT)信号,并将其发送给当前在shell中运行的所有进程

执行命令

sleep 100
^C

注:^代指Ctrl键

2.暂停进程

使用Ctrl+Z组合键会生成18(SIGTSTP)信号,停止shell中运行的任何进程

执行命令

sleep 100
^Z

当按键Ctrl+Z组合键时,bash shell会给出如下提示

[1]+  Stopped sleep 100
方括号中的数字时shell分配的作业号(job number)
shell将shell中运行的每个进程称为作业,并为每个作业分配唯一的作业号
如果shell回话中有已停止的作业,在退出shell时,bash会提醒你

常用操作

ps -l
查看已停止的作业,在S列中(进程状态)显示T的为已停止的作业
kill -9 PID
终止指定PID的作业,终止已停止作业的PID
通俗来讲,就是杀掉进程

16.1.3 捕获信号

命令格式:trap commands signals
命令说明:使用trap命令来指定shell脚本要监看并从shell中拦截的Linux信号

使用trap命令来忽略SIGINT信号

编写test1.sh脚本

#!/bin/bash

trap "echo 'Sorry!I have trappend Ctrl-C'" SIGINT

echo This is a test script

count=1
while [ $count -le 10 ]
do
    echo "Loop #$count"
    sleep 1
    count=$[ $count+1 ]
done

echo "This is the end of the test script"

16.1.4 捕获脚本退出

捕获shell脚本的退出EXIT信号

编写test2.sh脚本

#!/bin/bash

trap "echo Goodbye..." EXIT

count=1
while [ $count -le 5 ]
do
    echo "Loop #$count"
    sleep 1
    count=$[ $count+1 ]
done

16.1.5 修改或移除捕获

修改信号捕获,脚本仍然会根据最初的trap命令进行处理

编写test3.sh脚本

#!/bin/bash
#
trap "echo 'Sorry.. Ctrl+C is trapped.'" SIGINT
#
count=1
while [ $count -le 5 ]
do
    echo "Loop #$count" 
    sleep 1
    count=$[ $count+1 ]
done
#
trap "echo 'I modified the trap!'" SIGINT
#
count=1
while [ $count -le 5 ]
do
    echo "Loop #$count" 
    sleep 1
    count=$[ $count+1 ]
done

在trap和信号列表之间加上两个破折号删除已设置好的捕获并恢复默认行为

编写test3b.sh脚本

#!/bin/bash
#
trap "echo 'Sorry.. Ctrl+C is trapped.'" SIGINT
#
count=1
while [ $count -le 5 ]
do
    echo "Loop #$count" 
    sleep 1
    count=$[ $count+1 ]
done
#
# Remove the trap
trap -- SIGINT
echo "I just removed the trap"
#
count=1
while [ $count -le 5 ]
do
    echo "Loop #$count" 
    sleep 1
    count=$[ $count+1 ]
done

敲门:也可以在trap命令后使用单破折号来恢复信号的默认行为。单破折号和双破折号都可以正常发挥作用

16.2 以后台模式运行脚本

16.2.1 后台运行脚本

在命令后加个&符以后台模式运行shell脚本

编写test4.sh脚本

#!/bin/bash
count=1
while [ $count -le 10 ]
do
    sleep 1
    count=$[ $count+1 ]
done

执行命令

./test4.sh &

然后显示[1] 3231
方括号中的表示后台进程的作业号,后面的数字为进程的进程ID(PID)

当后台进程运行时,它仍然会使用终端显示器来显示STDOUT和STDERR消息

编写test5.sh脚本

#!/bin/bash
#
echo "Start the test script"
count=1
while [ $count -le 5 ]
do
    echo "Loop #$count"
    sleep 5
    count=$[ $count+1 ]
done
#
echo "Test script is complete"

当脚本在后台模式运行时,脚本的输出和输入的命令以及命令输出全都混在了一起,最好是将后台运行的脚本的STDOUT和STDERR进行重定向,避免杂乱的输出

16.2.2 运行多个后台作业

可以使用&符号的方法在命令行提示符下同时启动多个后台作业
使用ps命令查看所有脚本的运行状态
在终端会话中使用后台进程时一定要小心,当退出终端时,后台进程也会退出

16.2.3 在非控制台下运行脚本

命令格式:nohup ./test1.sh &
命令说明:使用nohup命令在终端会话中启动shell脚本,并让脚本一直以后台模式运行到结束,即使退出了终端会话,shell脚本也会一直运行

执行命令

nohup ./test1.sh &
cat nohup.out

说明

使用nohup启动shell脚本时,脚本会忽略终端会话发过来的SIGHUP信号
由于nohup命令会解除终端与进程的关联,进程也就不在同STDOUT和STDERR关联
nohup命令会自动将STDOUT和STDERR的消息重定向到当前目录下名为nohup.out的文件中
如果使用nohup命令运行了另一个脚本,则该脚本的输出会被追加到已有的nohup.out文件中

16.4 作业控制

启动/停止/终止以及恢复作业的这些功能统称为作业控制

16.4.1 查看作业

使用jobs命令查看shell当前正在处理的作业,脚本$$变量显示Linux系统分配给该脚本的PID

编写test10.sh脚本

#!/bin/bash
#
echo "Script Process ID: $$"
#
count=1
while [ $count -le 10 ]
do
    echo "Loop #$count"
    sleep 10
    count=$[ $count + 1 ]
done
#
echo "End of script..."
#

执行命令

./test10.sh > test10.out &
查看作业
jobs
查看作业的PID
jobs -l

jobs命令参数

参数:描述
-l:列出进程的PID以及作业号
-n:只列出上次shell发出的通知后改变了状态的作业
-p:只列出作业的PID
-r:只列出运行中的作业
-s:只列出已停止的作业

jobs命令输出中的加号和减号

带加号的作业会被当做默认作业
在使用作业控制命令时,如果未在命令行指定任何作业号,
    该作业会被当做作业控制命令的操作对象
当前的默认作业完成处理后,带减号的作业成为下一个默认作业
任何时候都只有一个带加号的作业和一个带减号的作业,
    不管shell中有多少个正在运行的作业

16.4.2 重启停止的作业

命令格式:bg 作业号
命令说明:以后台模式重启指定作业
命令格式:fg 作业号
命令说明:以前台模式重启指定作业

16.5 调整谦让度

在多任务操作系统中(Linux就是),内核负责将CPU时间分配给系统上运行的每个进程
调度优先级是内核分配给进程的CPU时间(相对于其他进程)
在Linux系统中,由shell启动的所有进程的调度优先级默认都是相同的
调度优先级是个整数值,从-20(最高优先级)到+19(最低优先级)
默认情况下,bash shell以优先级0来启动所有进程

敲门:最低值-20是最高优先级,而最高值19是最低优先级,这太容易记混了。只要记住那句俗语“好人难做”就行了。越是“好”或高的值,获得CPU时间的机会越低

16.5.1 nice命令

使用nice命令-n参数来指定新的优先级级别

执行命令

nice -n 10 ./test4.sh > test4.out &
查看作业信息
ps -p 3678 -o pid,ppid,ni,cmd
nice -10 ./test4.sh > test4.out &
ps -p 3706 -o pid,ppid,ni,cmd

16.5.2 renice命令

使用renice命令指定运行进程PID的优先级

执行命令

./test4.sh &
ps -p 3742 -o pid,ppid,ni,cmd
renice -n 10 -p 3742
ps -p 3742 -o pid,ppid,ni,cmd

renice命令的一些限制

只能对属于你的进程执行renice
只能通过renice降低进程的优先级
root用户可以通过renice来任意调整进程的优先级

16.6 定时运行作业

16.6.1 用at命令来计划执行作业

1.at命令的格式

命令格式:at [-f filename] time
命令说明:使用-f参数指定需要执行的脚本文件的文件名,time参数制定了什么时候运行

多种不同的时间格式

标准的小时和分钟格式,比如10:15
AP/PM指示符,比如10:15PM
特定可命名时间,比如now,noon,midnight或teatime(4PM)
标准日期格式,比如MMDDYY,MM/DD/YY或DD.MM.YY
文本日期,比如Junl4或Dec25,加不加年份均可
也可以指定时间增量
    当前时间+25min
    明天10:15PM
    10:15+7天

2.获取作业的输出

在Linux系统上运行时,显示器并不会关联到该作业。Linux系统会将STDOUT或STDERR的输出通过邮件系统发送给用户

编写test13.sh脚本

#!/bin/bash
echo "This script ran at $(date +%B%d,%T)"
echo
sleep 5
echo "This is the script end..."

执行命令

at -f test13.sh now

使用-M选项来屏蔽作业产生的输出信息

编写test13b.sh

#!/bin/bash
echo "This script ran at $(date +%B%d,%T)" > test13b.out
echo >> test13b.out
sleep 5
echo "This is the script end..." >> test13b.out

执行命令

at -M -f test13b.sh now
cat test13b.out

3.列出等待的作业

atq命令查看系统中有哪些作业在等待,显示作业列表
作业列表中显示了作业号,系统运行该作业的日期和时间及其所在的作业队列

4.删除作业

命令格式:atrm 作业号
命令说明:使用atrm删除指定作业

16.6.2 安排需要定期执行的脚本

1.cron时间表

命令格式:min hour dayofmonth month dayofweek command
命令说明:cron时间表采用一种特别的格式来指定作业何时运行

格式说明

dayofweek:文本(mon,tue,wed,thu,fri,sat,sun)或数值(0为周日,6为周六)
dayofmonth:表示月份中的日期值(1~31)

cron实例

在每天的10:15运行一个命令
15 10 * * * command
在每周一4:15PM运行的命令
15 16 * * 1 command
在每个月的第一天中午12点执行命令
00 12 1 * * command
在每个月的最后一天执行命令
00 12 * * * if [‘date +%d -d tomorrow’ = 01]; then;command
说明:在每天中午12点检查是不是当月的最后一天,如果是,cron将会运行该命令

执行命令

15 10 * * * /home/zc/test/unit16/test4.sh > test4.out

2.构建cron时间表

Linux提供了 crontab来处理cron时间表,使用cron时间表来运行安排好的任务

命令格式:crontab -l
命令说明:使用crontab -l列出已有的cron时间表

3.浏览cron目录

如果创建的脚本对精确的执行时间要求不高,则可以使用预配置的cron脚本目录

四个基本目录

hourly:每小时执行
daily:每天执行
monthly:每月执行
weekly:每周执行

执行命令

ls /etc/cron.*ly

4.anacron程序

cron程序只能保证,Linux系统在开机状态下,才执行定时作业,当Linux系统处于关机状态时,并不会去执行定时任务

使用anacron程序,当Linux系统关机,知道某个作业错过了执行时间,当Linux系统开机时,它会尽快运行作业

anacron程序只会处理位于cron目录的程序,如/etc/cron.monthly

命令格式:period delay identifier command
命令说明: period定义了作业多久运行一次,以天为单位。

注意:anacron程序不会处理执行时间小于一天的脚本,如位于/etc/cron.hourly的脚本

16.6.3 使用新shell启动脚本

每次启动一个新shell时,bash shell都会运行$HOME/.bashrc文件

验证

在$HOME/.bashrc文件的最后加入:echo "I'm in a new shell"
然后保存,关闭shell终端
重新打开shell终端时,可以看见该提示语

16.7 小结

本章主要讲解了linux中的信号控制,以后台模式执行脚本,指定时间执行脚本,修改脚本的优先级等。


妙手空空
1.3k 声望370 粉丝

博观而约取,厚积而薄发