1. 程式人生 > 實用技巧 >訊號處理 & expect免互動命令執行

訊號處理 & 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 [email protected] 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 [email protected] 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 [email protected]

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 [email protected]

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!!!"