目录
完整笔记请前往此处获取:https://download.csdn.net/download/qq_55908180/88366003
除了可以以实时模式在命令行界面直接运行脚本之外,还有一些选项可以用来控制脚本,这种方法包括向脚本发送信号、修改脚本优先级以及在脚本运行时切换到运行模式。
1.处理信号
1.1 重温Linux信号
信号 | 值 | 描述 |
1 | SIGHUP | 挂起进程 |
2 | SIGINT | 终止进程 |
3 | SIGQUIT | 停止进程 |
9 | SIGKILL | 无条件终止进程 |
15 | SIGTERM | 尽可能终止进程 |
17 | SIGSTOP | 无条件停止进程,但不是终止进程 |
18 | SIGTSTP | 停止或暂停进程,但不终止进程 |
19 | SIGCONT | 继续运行停止的进程 |
1.2 生成信号
Shell允许通过键盘上的组合键生成两种基本信号。
1、 中断进程
Ctrl+C组合键会生成SIGINT信号,并把它发送给当前在shell脚本中运行的所有进程;
2、 暂停进程
Ctrl+Z组合键会生成一个暂停信号(SIGTSTP),停止shell中运行的任何进程。注意,停止不是终止进程,停止进程会让程序继续保留在内存中,并且可以从上次停止的位置继续运行。
可以使用ps命令查看已停止的作业。
如果有已经停止的作业存在,但是你仍要退出shell,只要再输入一遍exit命令就可以了,shell会退出并终止该作业。若你已知已停作业的PID,也可以使用kill命令来发送一个SIGKILL信号。如:
1.3 捕获信号
也可以在信号出现时捕获并执行其他命令,trap命令允许指定shell脚本要监督并从shell中拦截Linux信号,只要脚本收到trap命令中列出的信号,则该信号就不再由shell处理,而是交给本地处理。trap命令的格式是:trap commands signals如:
#!/bin/bash
trap "echo ' Sorry! I have trapped 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 script"
1.4 捕获脚本退出
在trap命令后面加上EXIT信号,就可以在脚本退出时进行捕获。如:
#!/bin/bash
trap "echo Goodbye..." EXIT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$[ count + 1 ]
done
1.5 修改或移除捕获
想要在脚本的不同位置进行不同的捕获处理,只要重新使用带有新的选项的trap命令。如:
#!/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 "Second Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
在修改了捕获信号之后,脚本处理信号的方式发生了变化,但是如果一个信号是在捕获被修改前收到的,脚本就会根据最初的trap命令进行处理。
也可以删除已经设置好的捕获,只要在trap命令与希望恢复默认行为的信号列表之间加上两个破折号就行了。如:
#!/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 "Second Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
2、 以后台模式运行脚本
想要以后台模式运行脚本,只要在命令后面加一个&符就可以实现。如:
#!/bin/bash
count=1
while [ $count -le 10 ]
do
sleep 1
count=$[ $count + 1 ]
done
当&符放到命令后时,它会将命令和bash shell分离开来,把命令作为一个独立的后台进程运行。方括号的数字是分配的后台进程作业号,后面的数字是Linux系统分配的进程ID(PID)。记住:每一个进程都必须有一个唯一的PID。
在后台进程运行时,它仍会在终端显示STDOUT和STDERR消息。如:
#!/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进行重定向,避免这种杂乱的输出。
3 、在非控制台下运行脚本
可以使用nohup命令实现在终端会话中启动shell脚本,然后让脚本一直以后台模式运行到结束。nohup命令运行另外一个命令来阻断所有发送给该进程的SIGHUP信号,这会在退出终端会话时阻止进程退出。命令格式如下:
nohup ./test3 &
为了保存该命令产生的输出,nohup命令会自动将sTDouT和sTDERR的消息重定向到一个名为nohup.out的文件中。直接看例子:
4、作业控制
启动、停止、终止以及恢复作业的这些功能统称为作业控制。
4.1、查看作业
jobs命令是作业控制中的关键命令,jobs命令允许查看shell当前正在处理的作业。如:
脚本用$$变量来显示Linux系统分配给该脚本的PID。
使用jobs命令可以查看分配给shell的作业。jobs命令会显示这两个已停止/运行中的作业,以及它们的作业号和作业中使用的命令。如:
jobs命令的一些命令行参数如下:
参数 | 描述 |
-l | 列出进程的PID以及作业号 |
-n | 只列出上次shell发出通知后改变了状态的作业 |
-p | 只列出作业的PID |
-r | 只列出运行中的作业 |
-s | 只列出已停止的作业 |
4.2、重启停止的作业
在bash作业控制中,可以将已停止的作业作为后台进程或前台进程重启。前台进程会接管你当前工作的终端,所以在使用该功能时要小心了。
要以后台模式重启一个作业,可用bg命令加上作业号。如:
要以前台模式重启作业,可用带有作业号的fg命令。
5、调整谦让度
调度优先级( scheduling priority)是内核分配给进程的CPU时间。在Linux系统中,由shell启动的所有进程的调度优先级默认都是相同的。
调度优先级是个整数值,从-20(最高优先级)到+19(最低优先级)。默认情况下,bash shell以优先级0来启动所有进程。
5.1、 nice命令
nice命令允许你设置命令启动时的调度优先级。要让命令以更低的优先级运行,只要用nice的-n命令行来指定新的优先级级别。如:
注意:nice命令的-n选项并不是必须的,只需要在破折号后面跟上优先级就行了。
5.2、 renice命令
renice命令可以做到改变系统上已运行命令的优先级,它允许你指定运行进程的PID来改变它的优先级。如:
renice命令有限制:
1、只能对属于你的进程执行renice;
2、只能通过renice降低进程的优先级;
3、root用户可以通过renice来任意调整进程的优先级。
6、定时运行作业
Linux系统提供了多个在预选时间运行脚本的方法:at命令和cron表。
6.1、用at命令来计划执行作业
at命令允许指定Linux系统什么时候运行脚本。at的守护进程atd会以后台模式运行,检查作业队列来运行作业。
6.1.1、at命令的格式
at [-f filename] time
默认情况下,at命令会将STDIN的输人放到队列中。可以用-f参数来指定用于读取命令(脚本文件)的文件名。
time参数指定了Linux系统何时运行该作业。如果指定的时间已经错过,at
命令会在第二天的那个时间运行指定的作业。
at命令能够识别多种时间格式:
- 标准的小时和分钟制,如:9:30
- AM/PM形式,如:9:30PM
- 特殊的时间名词,如:now,noon,midnight等
等等…
6.1.2、获取作业的输出
Linux系统会将提交该作业的用户的电子邮件地址作为STDOUT和STDERR。任何发到STDOUT或STDERR的输出都会通过邮件系统发送给该用户。如:
#!/bin/bash
echo "This script ran at $(date +%B%d,%T)"
echo
sleep 5
echo "This is the script's end..."
使用e-mail作为at命令的输出极其不便。at命令利用sendmail应用程序来发送邮件。如果你的系统中没有安装sendmail,那就无法获得任何输出。所以,在使用at命令时,最好在脚本中对STDOUT和STDERR进行重定向。如:
#!/bin/bash
echo "This script ran at $(date +%B%d,%T)" >> test3a.out
echo
sleep 5
echo "This is the script's end..." >> test3a.out
6.1.3、列出等待的作业
atq命令可以查看系统中有哪些作业在等待。
6.1.4、删除作业
只要知道有哪些作业在作业队列中等待,就能用atrm命令来删除等待中的作业。
6.2、安排需要定期执行的脚本
用at命令在预设时间安排脚本执行非常好用,但是对于定期执行的脚本来说就比较麻烦。
Linux系统使用cron程序来安排要定期执行的作业。cron程序会在后台运行并检查一个特殊的表(被称作cron时间表),以获知已安排执行的作业。
6.2.1、cron时间表
cron时间表采用一种特别的格式来指定作业何时运行。其格式如下:
min hour dayofmonth month dayofweek command
cron时间允许使用特殊值、取值范围(如1~9)或者使用通配符(*)来指定条目。
1、如你想要每天的9:30运行一个命令,可以用cron时间条目:
30 9 * * * command
2、如果想每周一12:30运行的命令,可以:30 12 * * 1 command
可以使用文本值(mon、tue、wed、thu、fri、sat、sun)或者数值(0表示周日,6表示周六)来指定dayofweek
3、如果想要每月第一天上午10:00执行命令:00 10 1 * * command
Dayofmonth表项指定月份中的日期值(1~31)
注意:命令列表必须指定要运行的命令或脚本的全路径名。当然,也可以添加任何想要添加的命令行参数和重定向符号。
6.2.2、构建cron时间表
每个系统用户(包括root用户)都可以用自己的cron时间表来运行安排好的任务。Linux提供了crontab命令来处理cron时间表。要列出已有的cron时间表,可以用-l选项。如:
用户的cron时间文件默认不存在,想要添加条目,可以使用-e选项。
6.2.3、浏览cron目录
如果创建的脚本对精确的执行时间要求不高,用预配置的cron脚本目录会更方便。有4个基本目录:hourly、daily、 monthly和weekly。如:
因此,如果脚本需要每天运行一次,只要将脚本复制到daily目录,cron就会每天执行它。
6.2.4、anacron程序
如果Linux系统处于关机状态,但是此时有作业在这个时间安排了运行,则就会错过执行时间。可以使用anacron程序,如果anacron知道某个作业错过了执行时间,它会尽快运行该作业。这意味着如果Linux系统关机了几天,当它再次开机时,原定在关机期间运行的作业会自动运行。注意:anacron程序只会处理位于cron目录的程序,
anacron时间表的基本格式如下:
period delay identifier command
period条目定义了作业多久运行一次,以天为单位。
delay条目会指定系统启动后anacron程序需要等待多少分钟再开始运行错过的脚本
command条目包含了run-parts程序和一个cron脚本目录名。run-parts程序负责运行目录中传给它的任何脚本。
identifier条目是一种特别的非空字符串,它用于唯一标识日志消息和错误邮件中的作业。
6.3、使用新shell启动脚本
每次启动一个新shell时, bash shell都会运行.bashrc文件。可以这样来验证:在主目录下的.bashrc文件中加入一条简单的echo语句,然后启动一个新shell。
.bashrc文件通常也是通过某个bash启动文件来运行的。因为.bashrc文件会运行两次:一次是当你登入bash shell时,另一次是当你启动一个bash shell时。如果你需要一个脚本在两个时刻都得以运行,可以把这个脚本放进该文件中。