信号处理 & expect免交互命令执行

一 信号处理

# 1 什么是信号
	由键盘组合键或者kill命令发出操作称之为信号
    
    信号是发送给进程的,进程在收到信号后会作出默认的响应
    
# 2 为何要在进程内处理信号
    进程在收到信号后会有默认的响应,
    如果我们想改变进程在接收到信号后的反应,那么需要在进程内捕捉信号执行我们自定义的操作
    
# 3 主要的应用场景:
    	在进程内捕捉终止信号,然后忽略掉,从而达到让进程不受外界干扰正常运行完毕的效果
        
        ps:不是所有的信号都可以被捕捉,比如-9
        
        
3、如何处理信号

    trap "捕捉到信号之后要执行的命令" 信号
    trap "" 信号		                        # 如不指定执行信息则当做不做处理
    trap "" 信号1 信号2 信号3 			# 多个信号都不做处理

trap信号列表

信号 说明
HUP 挂起,通常因终端掉线或用户退出而引发
INT 中断,通常因按下Crtl+C组合健而引发
QUIT 退出,通常因某些严重的执行错误而引发
TERM 终止,通常在系统关机时发送
TSTP 停止进程的运行,但该信号可以被处理和忽略,用户健入SUSP字符时(通常是Ctrl-Z)发出这个信号
ABRT 中止,通常因某些严重的执行错误而引发
  • 示例如
# 使用此方式执行脚本,对键盘执行的ctrl+c ctrl+z等其他操作都不会进行操作,以往执行ctrl+c都是停止。

· 这里主要实现对脚本循环执行红绿灯,并且此脚本执行过程中不受下方信号影响。
[root@tcy day07]# cat 3.sh 
#!/bin/bash

trap "" INT QUIT HUP TERM TSTP				# 当执行这些信号都不会做任何操作

clear
n=0

while :
do
    [ $n -eq 0 ] && n=1 || n=0    

    if [ $n -eq 1 ];then
        echo -e "\033[31m 红灯亮 \033[0m"
    else
        echo -e "\033[32m 绿灯亮 \033[0m"
    fi
    
    sleep 0.5
    clear
done 

HUP信号的处理:让一个进程脱离当前会话窗口运行

nohup脱离父进程

  • (需将其终端关闭,才能将父进程改变为系统进程,否则为终端进程)

    # 在终端2内
    [root@tcy ~]# echo $$
    12479
    [root@tcy ~]# nohup ping www.baidu.com &
    
    # 关闭终端2
    
    # 在终端1内仍然可以看到进程(但其父进程为系统进程)
    [root@tcy ~]# ps -ef |grep [p]ing
    root      13169      1  0 18:58 ?        00:00:00 ping www.baidu.com
    
  • setsid(直接让父进程为系统进程)

    setsid ping www.baidu.com &
    
  • (进程 &) 直接让父进程为系统进程

    (ping www.tcy.com &)
    [root@db01 ~]# ps -ef|grep tcy
    root       8333      1  0 22:46 pts/1    00:00:00 ping www.tcy.com
    root       8360   8336  0 22:46 pts/2    00:00:00 grep --color=auto tcy
    

二 expect

expect介绍

在使用expect时,基本上都是和以下四个命令打交道:

命令 作用
spawn 启动新的进程
expect 从进程接收字符串
send 用于向进程发送字符串
interact 允许用户交互
  • spawn命令用来启动新的进程,spawn后的expectsend命令都是和使用spawn启动的新进程进行交互。
  • expect通常用来等待一个进程的反馈,我们根据进程的反馈,再使用send命令发送对应的交互命令。
  • send命令接收一个字符串参数,并将该参数发送到进程。
  • interact命令用的其实不是很多,一般情况下使用spawnexpectsend和命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。比如我们使用spawnsendexpect命令完成了ftp登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在ftp命令行状态,以便手动的执行后续命令,此时使用interact命令就可以很好的完成这个任务。

expect基本使用

# 前期需要安装expect安装包
[root@db01 day08]# yum install -y expect

# send指令提交方式(两者都可对指令进行提交)
\n
\r

[root@tcy day07]# cat 4.sh 
#!/usr/bin/expect 					# 这里虽然是脚本,但是需要指定解释器为expect
spawn ssh root@127.0.0.1 hostname	                # 执行进程操作指令
expect "yes/no"						# 等待进程反馈,匹配yes/no的指令
send "yes\r"						# 根据expect匹配的指令进行操作,也就是直接帮助yes提交

expect "assword"					# 继续等待进程反馈,屁屁额assword指令
send "1\n"				                # 根据匹配的指令进行1操作,这里也就是我的密码

expect eof						# 结束交互指令

# 总结:
这种操作存在弊端,只适用于第一次连接,如第二次进行ssh连接,可忽略yes步骤,直接输入密码即可,expect比较愚蠢,
不会只能匹配,而是在第二次连接时当需要输入密码,直接也将第一次匹配的yes直接发送,也就导致了后续的报错。
所以这里为了解决此问题,可参考expect一问一答中的案例操作。

强调:我们此时编写的是expect脚本,不要用sh 4.sh执行,可以./4.sh运行,也可以expect 4.sh运行

expect 一问一答(推荐使用)

# 这里会根据进程指令自动匹配,所以需要将操作匹配指令写入同一个expect中进行处理。

#!/usr/bin/expect 
spawn ssh root@127.0.0.1 hostname

expect {
    "yes/no" {send "yes\n";exp_continue}    
    "*assword" {send "1\n";}
}

expect eof

远程登录主机执行多条命令

# 可免交互式登录主机执行多条语句,注意,这里都是expect语句,不能按照shell语句方式执行

[root@tcy day07]# cat 6.sh 
#!/usr/bin/expect 

spawn ssh root@127.0.0.1

expect {
    "yes/no" {send "yes\n";exp_continue}    
    "*assword" {send "1\n";}
}

expect {
    "#" {send "ls\n"}			# 这里为匹配#交互式指令,到匹配到就执行ls命令
}

expect {
    "*root*" {send "pwd\n"}		# 这里为匹配root交互式指令,匹配到就执行pwd指令
}

expect {
    "#" {send "exit\n"}			# 这里为匹配# 指令,匹配到就执行exit指令,相当于回到自己的终端
}

expect eof		                # 结束交互式操作,但还在远程的终端中,超时才会自动退出

interact(了解)

[root@tcy day07]# cat 7.sh 
#!/usr/bin/expect 

spawn ssh tcy@127.0.0.1

expect {
    "yes/no" {send "yes\n";exp_continue}    
    "*assword" {send "1\n";}
}

expect {
    "*tcy*" {send "ls\n"}
}

expect {
    "*tcy*" {send "pwd\n"}
}

interact			 # 运行完以上指令,不进行超时退出,任然停留在远程终端中			
expect eof	


在expect脚本中定义变量

# 使用的并不是bash解释器,所以需要expect自身语法。
#!/usr/bin/expect 
set user "root"					         # 类似于bash的定义变量user=root
set pass "1"
set ip "127.0.0.1"
set cmd "hostname"

spawn ssh $user@$ip $cmd				 # 调用上方定义变量开启进程

expect {
    "yes/no" {send "yes\n";exp_continue}    
    "*assword" {send "$pass\n";}
}

expect eof

把expect引入shell脚本(推荐使用)

# 单学expect较为复杂,可将expect引入bash中。

#!/bin/bash							# 使用bash解释器

user="root"							# 使用bash的方式定义变量
pass="1"
ip="127.0.0.1"
cmd="hostname"

expect << EOF							# 引expect在bash中也是一个命令,所以将其
spawn ssh $user@$ip $cmd				        # 内容放入一个内容体当中

expect {
    "yes/no" {send "yes\n";exp_continue}    
    "*assword" {send "$pass\n";}
}

expect eof
EOF

echo "success!!!"						
posted @ 2020-09-01 15:41  元气少女郭德纲!!  阅读(705)  评论(0编辑  收藏  举报