《Shell 编程》14_Linux 信号及 Expect 自动化交互式程序
标签(空格分隔): Shell
文章目录
14.1 Linux 信号及 trap 命令
14.1.1 信号知识
信号介绍
- 运行 shell 脚本程序时,如果按下快捷键 Ctrl+c 或 Ctrl+x(x 为其他字符),程序就会立刻终止运行。
- 在有些情况下,我们并不希望 shell 脚本在运行时被信号中断,此时就可以使用屏蔽信号手段,让程序忽略用户输入的信号指令,从而继续运行 Shell 脚本程序。
- 简单地说,Linux 信号是由一个整数构成的异步消息,它可以由某个进程发给其他的进程,也可以在用户按下特定键发生某种异常事件时,由系统发给某个进程。
信号列表
[root@web001 ~]# kill -l 或 trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
Linux 系统的重要信号及说明
signal | description |
---|---|
HUP(1) | 挂起,通常因中端掉线或用户退出而引发 |
INT(2) | 中断,通常因按下 Ctrl+c 组合键而引发 |
QUIT(3) | 退出,通常因按下 Ctrl+\ 组合键而引发 |
ABRT(6) | 中止,通常因某些严重的执行错误而引发 |
ALRM(14) | 报警,通常用来处理超时 |
TERM(15) | 终止,通常在系统关机时发送 |
TSTP(20) | 停止进程的运行,但该信号可以被处理和忽略,通常因按下 Ctrl+z 组合键而引发 |
14.1.2 使用 trap 控制信号
-
trap 命令的一种常见用途是在脚本程序被中断时完成清理工作,或者屏蔽用户非法使用的某些信号。在使用信号名时需要省略 SIG 前缀。
-
trap 命令的使用语法如下:
trap command signal
- signal 是指接收到的信号,command 是指接收到该信号应采取的行动,即:
trap '命令;命令' 信号编号或信号名
例 14-1
测试 trap 命令捕获 Ctrl+c 信号
[root@web001 ~]# trap 'echo ylt' 2
[root@web001 ~]# ^Cylt
[root@web001 ~]# trap "echo ylt1" INT
[root@web001 ~]# ^Cylt1
用 stty -a 可以列出中断信号与键盘的对应信息,如下:
[root@web001 ~]# stty -a
speed 38400 baud; rows 38; columns 138; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
例 14-2
测试按下 Ctrl+c 组合键而引发的 INT(2) 信号。
[root@web001 ~]# trap "" 2 #<== 执行动作处为空,此命令可以用来屏蔽与数字对应的 Ctrl+c 信号
[root@web001 ~]# #<== 此时执行 Ctrl+c 无任何反应
[root@web001 ~]# trap ":" 2 #<== 恢复 Ctrl+c 信号
[root@web001 ~]# ^C
[root@web001 ~]# trap "echo -n 'you are typing ctrl+c'" 2
[root@web001 ~]# ^Cyou are typing ctrl+c
例 14-3
同时处理多个信号
- 执行任何一个对应信号的事件时,都会执行前面对应的动作,因为动作为空,所以执行后没有任何反应。
[root@web001 ~]# trap "" 1 2 3 20 15 #<== 执行这些数字信号,什么都不做
[root@web001 ~]# trap ":" 1 2 3 20 15 #<== 执行这些数字信号,恢复对应功能
[root@web001 ~]# ^C
[root@web001 ~]# trap "" HUP INT QUIT TSTP TERM #<== 执行这些名称信号,什么都不做
[root@web001 ~]# trap ":" HUP INT QUIT TSTP TERM #<== 执行这些名称信号,恢复对应功能
[root@web001 ~]# trap "" `echo {1..64}` #<== 屏蔽 1-64 的所有数字信号
例 14-4
开发脚本实现触发信号后清理文件功能。
#!/bin/bash
trap "find /tmp -type f -name "ylt_*"|xargs rm -f && exit" INT
while true
do
touch /tmp/ylt_$(date +%F-%H-%M-%S)
sleep 3
ls -l /tmp/ylt*
done
14.2 Expect 自动化交互式程序
14.2.1 Expect 程序自动交互的重要命令
Expect 介绍
-
Expect 是一个用来实现自动交互功能的软件套件(Expect is a software suit fir automating interactive tools),是基于 TCL(Tool Comamnd Language)的脚本编程工具。
-
Expect 的自动交互工作流程:
spawn 启动指定进程 -> expect 获取期待的关键字 -> send 向指定进程发送指定字符 -> 进程执行完毕,退出结束。
spawn 命令
-
在 Expect 自动交互程序执行的过程中,spawn 命令是一开始就需要使用的命令。通过 spawn 执行一个命令或程序,之后所有的 Expect 操作都会在这个执行过的命令或程序中进程,包括自动交互功能。
-
spawn 命令的语法为:
spawn [option] [需要自动交互的命令或程序]
- 在 spawn 命令后面可直接加上要执行的命令或程序,也可加上一些选项,如下:
-open:表示启动文件进程
-ignore:表示忽略某些信号
expect 命令
-
在 Expect 自动交互程序的执行过程中,当使用 spawn 命令执行一个命令或程序之后,会提示某些交互式信息,expect 命令的作用就是获取 spawn 命令执行后的信息,看看是否和其事先指定的相匹配,一旦匹配上指定的内容就执行 expect 后面的动作。
-
expect 命令也有一些选项,相对用得较多的是 -re ,表示四使用正则表达式的方式来匹配。
-
expect 命令的语法为:
expect 表达式 [动作]
expect 命令实践
例 14-5
执行 ssh 命令远程获取服务器负载值,并要求实现自动输入密码
方法 1:将 expect 和 send 放在一行
#!/bin/bash
spawn ssh -p 52017 root@192.168.2.144 uptime
expect "*password" {send "123456\n"} #<== 如果 ssh 命令输出匹配 *password,就发送 123456 给系统
expect eof #<== 要想输出结果,还必须加 eof ,表示 expect 结束
方法2:匹配的动作也可以放在下一行,此时不需要大括号
#!/bin/bash
spawn ssh -p 52017 root@192.168.2.144 uptime
expect "*password:"
send "123456\n"
expect eof
执行结果:
[root@web001 scripts]# expect 321.exp
spawn ssh -p 52017 root@192.168.2.144 uptime
root@192.168.2.144's password:
16:38:41 up 13 min, 2 users, load average: 0.00, 0.01, 0.01
例 14-6
执行 ssh 命令获取服务器负载,并自动输入 “yes” 及用户密码。
#!/usr/bin/expect
spawn ssh -p 52017 root@192.168.2.144 uptime
expect { #<== expect 与 { 之间需要空格
"yes/no" {exp_send "yes\r";exp_continue}
"*password" {exp_send "123456\r"}
}
expect eof
- exp_send 与 send 类似
- \r(回车)与 \n(换行)类似
- 匹配多个字符串,需要在每次匹配并执行动作后,加上 exp_continue
例 14-7
利用 expect 响应 Shell 脚本中的多个 read 读入
[root@web001 scripts]# cat 322.sh
#!/bin/bash
read -p 'pls input your username:' name
read -p 'pls input your password:' pass
echo -n "your name is $name,"
echo "your password is $pass."
[root@web001 scripts]# expect 322.exp
spawn /bin/sh 322.sh
pls input your username:ylt
pls input your password:123456
your name is ylt,your password is 123456.
send 命令
- exp_send 和 send 命令类似,都是 Expect 中的动作命令,用法类似。即在 expect 命令匹配指定的字符串后,发送指定的字符串给系统,这些命令可以支持一些特殊的转义符号,例如 \r 回车,\n 表示换行,\t 表示制表符。
- send 命令有几个可用的参数,如下:
-i:指定 spawn_id,用来向不同的 spawn_id 进程发送命令,是进行多程序控制的参数。
-s:s 代表 slowly,即控制发送的速度,使用的时候要与 expect 中的变量 send_slow 相关联。
exp_continue 命令
- 一般处于 expect 命令中,属于一种动作命令,一般用在匹配多次字符串的动作中。
- 如果需要一次匹配多个字符串,那么不同的匹配之间就要加上 exp_continue,否则 expect 将不会自动输入指定的字符串。最后一个结尾就不需要加上 exp_continue 了,因为匹配都完成了。
send_user 命令
- send_user 命令可用来打印 Expect 脚本信息,类似 Shell 里的 echo 命令,而默认的 send、exp_send 命令都是将字符串输出到 Expect 程序中去。
[root@web001 scripts]# cat 324.exp
#!/usr/bin/expect
send_user "I am ylt.\n"
send_user "I am learning shell,\t"
send_user "My blog is ...\n"
[root@web001 scripts]# expect 324.exp
I am ylt.
I am learning shell, My blog is ...
exit 命令
- exit 命令的功能类似于 Shell 中的 exit,即直接退出 Expect 脚本。
- 除了最基本的退出脚本功能之外,还可以利用这个命令对脚本做一些关闭前的清理和提示工作。
[root@web001 scripts]# cat 325.exp
#!/usr/bin/expect
send_user "I am ylt.\n"
send_user "I am learning shell,\t"
send_user "My blog is ...\n"
exit -onexit {
send_user "Good bye.\n"
}
[root@web001 scripts]# expect 325.exp
I am ylt.
I am learning shell, My blog is ...
Good bye.
14.2.2 Expect 程序变量
1)普通变量
- 定义变量的基本语法如下:
set 变量名 变量值
- 打印变量的基本语法如下:
puts $变量名
2)特殊参数变量
- 在 Expect 里也有与 shell 脚本里的 $0、$1、$# 等类似的特殊参数变量,用于接收及控制 Expect 脚本传参。
- 在 Expect 中 $argv 表示参数数组,可以使用 [lindex $argv n] 接收脚本传参,n 从 0 开始,分别表示第一个 [lindex $argv 0]参数、第二个 [lindex $argv 1] 参数…
- $argc 表示传参的个数
- $argv0 表示脚本的名字
set <变量名称> [lindex \$argv <param index>]
[root@web001 scripts]# cat 326.exp
#!/usr/bin/expect
set file [lindex $argv 0]
set host [lindex $argv 1]
send_user "$file\t$host\n"
puts "$file\t$host\n"
[root@web001 scripts]# expect 326.exp ylt.log 192.168.2.188
ylt.log 192.168.2.188
ylt.log 192.168.2.188
14.2.3 Expect 程序中的 if 条件语句
- Expect 程序中 if 条件语句的基本语法为:
if {条件表达式} {
指令
}
或
if {条件表达式} {
指令
} else {
指令
}
14.2.4 Expect 中的关键字
1)eof 关键字(end of file)
- 用于匹配结束符。
2)timeout 关键字
- timeout 是 Expect 中的一个控制时间的关键字变量,它是一个全局性的时间控制开关,可以通过为这个变量赋值来规定整个 Expect 操作的时间。
- 注意这个变量是服务于 Expect 全局的,而不是某一条命令,即使命令没有任何错误,到了时间仍会激活这个变量,此外,到时间后还会激活一个处理及提示信息开关。
- timeout 变量设置为 0 表示立即超时,-1 表示永不超时。
#!/usr/bin/expect
spawn ssh root@192.168.2.144 uptime
set timeout 30
expect "yes/no" {exp_send "yes\r";exp_continue}
expect timeout {puts "Request timeout."'return}
或
#!/usr/bin/expect
spawn ssh root@192.168.2.144 uptime
expct {
-timeout 3
"yes/no" {exp_send "yes\r";exp_continue}
timeout {puts "Request timeout.";return}
}