expect高級用法實例

  • 場景描述

使用expect自動化腳本Telnet遠端登陸device端,在同一個session中發送多條命令順序執行,結束後返回命令集在終端執行所產生的log,交給Python處理。

  • 示例技術

  1. expect 中 if 使用
  2. expect 正則使用
  3. tcprelay + telnet
  4. python 調用 expect
  • 源碼

  1. auto_telnet.exp
#!/usr/bin/expect 
# ****************************************
# @Author: Cyril
# @Create: 19/02/23
# This is a auto script for exec telnet connection, Using it to replace 'scout remote'
# Usage: ./auto_telnet.rep <TelnetPort> <OSCMD_len>
# ****************************************

if {$argc<2 } {
        send_user "Error: Parameters incorrect \n"
        send_user "Usage: ./auto_telnet.rep <TelnetPort> <OSCMD_len> <OSCMD 1> <OSCMD 2> * * *\n"
        exit
}

set TelnetPort [lindex $argv 0]
set OSCMD_len [lindex $argv 1]

set param_num [expr {$argc-2}]
if { $OSCMD_len!=$param_num } {
	send_user "Parameters num incorrect \n"
	exit
}

## -1 means never timeout

set user "root"
set pwd "alpine"

set prompt "iPhone:~ root#"
#set prompt "gdlocal$ "

#send_tty命令用來實現在終端上顯示提示符字串
#send_tty "$prompt"

set timeout 30
spawn telnet localhost $TelnetPort
exec sleep 1
expect { 
	-re "Are you sure you want to continue connecting (yes/no)?" { send "yes\r"; exp_continue }
	-re "login:" { send "$user\r"; exp_continue }
	-re "Password:" { send "$pwd\r" }
	eof { 
		send_error "Telnet conn disconnected. Exit.";
		exit 
	}
}

sleep 1

set index [expr {$argc - 1}]
for {set i 3} {$i <= $index} {incr i} {
	expect $prompt {	
		puts "index$i = [lindex $argv $i]"
		send "[lindex $argv $i] \r"
	} timeout 3 {
		send_user "Timeout...exit";
		exit
	} eof {
		send_error "EOF...finish";
		exit
	}
}

send_user "Finish"

  1. Tools.py
......
def getOSLogs(cableName, cLogsList):
	loc_id = getLocId(cableName)
	## init tcp_port value to 10000
	tcp_port = 10000
	## tcprelay process id (str)
	tcp_proc_id = ""

	try:
		## 1. Get eixsts tcprelay_ports list
		res, tcp_port_list = readCMD(["lsof -i tcp | grep tcprelay | awk -F ':' '{print $2}' | awk -F ' ' '{print $1}' | awk -F/ '!a[$1,$2]++'"], True)
		if res:
			## Produce a legal tcp_port for a new tcprelay connection.
			while (str(tcp_port+23) in tcp_port_list):
				tcp_port = tcp_port + 1
        
		## 2. Start tcprelay monitor.
		res, rev = readCMD(["tcprelay --locationid %s --portoffset %s 873 23 &" %(loc_id, tcp_port_list) ], True)
		#res, rev = readCMD(["/usr/local/bin/tcprelay --portoffset  '%d' '%d' '%d' &" %(tcp_port,  873, 23)], True, 1)
	        #    if res: ## 'res' is always False, should not be judged.
        
		## 3. Get Current tcprelay proc_id
		telnet_port = tcp_port + 23
		res, rev = readCMD( ["lsof -i tcp:%s | awk -F ' ' '{print $2}' | sed '/PID/d' | awk -F/ '!a[$1,$2]++'" %(telnet_port)], True)
		tcp_proc_id = rev[0]
		writeLogs("Current tcprelay process_id = %s" %tcp_proc_id)
        
        
		## 4. Open telnet connection
		telnet_cmd = script_path + "/auto_telnet.exp %s %s" %( str(telnet_port), str(cLogsList.count))
	#	for i in cLogsList.count:
	#		telnet_cmd = telnet_cmd + " " + str(cLogsList[i])
		writeLogs("DEBUG 63: telnet_cmd = %s" %telnet_cmd)
		#telnet_cmd = script_path + "/auto_telnet.exp ls pwd"
		#res, telnet_rev = readCMD( [script_path+"/auto_telnet.exp %s %s" %(str(tcp_port + 23), str(cLogsList.count)) ], True)
		telnet_rev_list = []
	        #	cLogsList.append("exit")
        	for item in cLogsList:
			telnet_cmd = telnet_cmd + ' "%s" "%s" ' %( telnet_port, item)
			res, rev = readCMD( [telnet_cmd ], True)
			telnet_rev_list.append(rev)
#			#yield telnet_rev_list
		        if "Connection closed by foreign host." in rev and "Connection closed by foreign host." not in rev[-1]:
				writeLogs("Telnet port-%s open failed, OS cmd executed failed." %(telnet_port) )
				kill_tcprelay(tcp_proc_id)
				print("rev=None")
	except Exception as e:
        	writeLogs(e)
	        # Kill Tcprelay conn
        	kill_tcprelay(tcp_proc_id)
		print("rev=None")
		return list_to_str(telnet_rev_list)
	else:
		# Kill Tcprelay conn
		kill_tcprelay(tcp_proc_id)
		print("rev=%s" %list_to_str(telnet_rev_list))

  1. Python 執行Shell命令函數
def readCMD(args=[], isShell=True, timeout=-1):
        '''
        #Running the command and read String from stdout.
        #@param args(list): cmd script path & cmd params
        #@param isShell(Bool): The cmd is shell cmd or not.
        #@param timeout(int): set timeout(must > 0), default -1 means never timeout
        #@return (res, rev): res: result status code
        #                   rev: result string
        '''
        if timeout < 0 and timeout != -1:
                writeLogs("Timeout setting value illegal")
                exit(255)
        import time,signal
        rev = []
        p = subprocess.Popen( args, shell=isShell, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        while True:
                if timeout<=0:
                        buff = p.stdout.readline().strip().replace("\r\n","")
                        if p.poll() != None:
                                if buff == '':
                                        break;
                        if buff != '':
                                buff.strip().replace("\n","")
                                rev.append(buff)
                                print(buff)
                                writeLogs_EXP(buff)
                else:
                        try:
                                signal.signal(signal.SIGALRM, handler)
                                signal.alarm(timeout)
                                buff = p.stdout.readline().strip().replace("\r\n","")
                                if p.poll() != None:
                                        if buff == '':
                                                break;
                                if buff != '':
#                                       buff.strip().replace("\n","")
                                        rev.append(buff)
                                        print(buff)
                                        writeLogs_EXP(buff)

                                signal.alarm(0)
                        except AssertionError:
                                writeLogs_EXP("CMDError: '%s' timeout" %(args[0]))
                                #print("rev=",rev)
                                return (False, rev)

        if p.wait() == 0:  ## get cmd result value
                res = True
        else:
                res = False
        return (res, rev)         ## res(Bool): The cmd is running successful?
                                ## rev(String): The cmd result string.
  1. Python調用執行:
getOSLogs( "/dev/cu.serial2",  ['ls', 'pwd'])

這裏只是匆忙記錄一下,有空再詳細介紹。

參考:

1>. Expect 手冊中文版 https://blog.51cto.com/lielie/1537942 (轉載)

tips:更詳細的expect介紹請直接查看man expect

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章