【Linux】命令expect使用詳解

LiuYanYGZ發表於2024-08-31

一、概述
1.1 命令簡介
expect 是由Don Libes基於Tcl(Tool Command Language )語言開發的,是一種指令碼語言,主要應用於自動化互動式操作的場景,藉助Expect處理互動的命令,可以將互動過程如:ssh登入,ftp登入等寫在一個指令碼上,使之自動化完成。尤其適用於需要對多臺伺服器執行相同操作的環境中,可以大大提高系統管理人員的工作效率。

1.2 使用場景
(1)根據預定標準回答其問題,回答“是”、“否”或將控制權交還給您

(2)遠端連線裝置並執行自動化操作

(3)需要人機互動的地方,如果提前知道應該輸入什麼指令都可以使用expect 工具

1.3 expect命令安裝
yum install expect -y
二、expect使用原理
2.1 命令原理介紹
spawn啟動指定程序—expect獲取指定關鍵字—send向指定程式傳送指定字元—執行完成退出

spawn命令
spawm命令就是用來啟動新的程序的。spawn後的send和expect命令都是和spawn開啟的程序進行互動的、

send命令
send命令接收一個字串引數,並將該引數傳送到程序,這個過程類似模擬人類輸入密碼

interact命令
結合spawn、expect、send自動化的完成很多工,interact命令可以在適當的時候進行任務的干預,比如下載完ftp檔案時,仍然可以停留在ftp命令列狀態,以便手動的執行後續命令

三、expect使用語法
3.1 expect 啟用選項
-c 執行指令碼前先執行的命令,可多次使用
-d debug模式,可以在執行時輸出一些診斷資訊,與在指令碼開始處使用exp_internal 1相似。
-D 啟用交換調式器,可設一整數引數。
-f 從檔案讀取命令,僅用於使用#!時。如果檔名為"-",則從stdin讀取(使用"./-"從檔名為-的檔案讀取)。
-i 互動式輸入命令,使用"exit"或"EOF"退出輸入狀態
-- 標示選項結束(如果你需要傳遞與expect選項相似的引數給指令碼時),可放到#!行:#!/usr/bin/expect --
-v 顯示expect版本資訊
3.2 expect命令引數
spawn: 互動程式開始,執行後面的命令或程式。需要進入到expect環境才可以執行,不能直接在shell環境下直接執行
set timeout n : 設定超時時間,表示該指令碼程式碼需在n秒鐘內完成,如果超過,則退出。用來防止ssh遠端主機網路不可達時卡住及在遠端主機執行命令宕住。如果設定為-1表示不會超時
set: 定義變數
$argv expect指令碼可以接受bash的外部傳參,可以使用[ lindex $argv n ]n為0表示第一個傳參,為1表示第二個傳參,以此類推
expect 從互動程式程序中指定接收資訊, 如果匹配成功, 就執行send的指令互動;否則等待timeout秒後自動退出expect語句
send 如果匹配到expect接受到的資訊,就將send中的指令互動傳遞,執行互動動作。結尾處加上\r表示如果出現異常等待的狀態可以進行核查
exp_continue 表示迴圈式匹配,通常匹配之後都會退出語句,但如果有exp_continue則可以不斷迴圈匹配,輸入多條命令,簡化寫法。
exit 退出expect指令碼
expect eof: spawn程序結束後會向expect傳送eof,接收到eof代表該程序結束
interact 執行完程式碼後保持互動狀態,將控制權交給使用者。沒有該命令執行完後自動退出而不是留在遠端終端上
puts 輸出變數
四、實戰案例
4.1 登入遠端伺服器並在遠端伺服器上執行命令

#!/usr/bin/expect
 
spawn ssh root@192.168.2.161 df -h
expect "*password:"
send "winner@001\n"
expect eof

執行結果如下圖:

4.2 本機免密實現

#! /bin/bash
#
# Author: kangll
# CreateTime: 2023-11-10
# Desc: 基礎環境配置,包括伺服器設定,JDK,免密,kerberos配置
# 可擴充套件到批次操作 
#
 
#set -x
BASEDIR=$(cd "$(dirname "$0")"; pwd)
# 載入配置
source  $BASEDIR/config/global.sh
ssh_networkname=(windp-aio)
ssh_passwd=winner@#2023
 
########################
# 生成本地ssh公鑰
########################
create_ssh_pub(){
    echo "生成本地ssh公鑰"
    /usr/bin/expect << eof
    # 設定捕獲字串後,期待回覆的超時時間
    set timeout 30
    # 執行命令開啟一個新的程序
    spawn ssh-keygen -t rsa -b 1024
     
    ## 開始進連續捕獲
    expect    {
        ".ssh/id_rsa)"      { send "\n";  exp_continue }
        "Overwrite (y/n)?"  { send "y\n"; exp_continue }
        "no passphrase):"   { send "\n";  exp_continue }
        "passphrase again:" { send "\n";  exp_continue }
    }
eof
}
 
 
########################
# 定義複製ssh公鑰方法
########################
copy_ssh(){
       
  if [ ! -f /root/.ssh/id_rsa.pub ];then
       create_ssh_pub
  fi
    echo "複製公鑰到對應的主機上"
    /usr/bin/expect << eof
    # 設定捕獲字串後,期待回覆的超時時間
    set timeout 30
    # 命令執行
    spawn ssh-copy-id -i /root/.ssh/id_rsa.pub $1@$2
     
    ## 開始進連續捕獲
    expect    {
        "connecting (yes/no)?" { send "yes\n";  exp_continue }
        "s password:"          { send "${ssh_passwd}\n"; exp_continue }
    }
eof
}
 
########################
# 配置免密
########################
config_ssh() {
    # 主機遍歷
    for name in ${ssh_networkname[*]};do
        timeout 5 ssh root@${name} "echo ${name}: 'This is success!'"
        if [[ $? -ne 0 ]];then
            echo "複製檔案到: ${name}"
            copy_ssh root ${name} > /dev/null
        fi
    done
         
        echo "********** ssh installation completed **********"
}
 
# 配置root使用者免密 
config_ssh

4.3 自動生成kerberos使用者的keytab認證檔案

#! /bin/bash
#
# Author: kangll
# CreateTime: 2023-11-10
# Desc: 基礎環境配置,包括伺服器設定,JDK,免密,kerberos配置
# 可擴充套件到批次操作 
#
# public 主機名和root密碼 
ip=$(ip addr show | grep -E 'inet [0-9]' | awk '{print $2}' | awk -F '/' '{print $1}' | sed -n '$p')
ssh_hosts=${ip}
ssh_networkname=(windp-aio)
# global.sh 配置檔案中獲取
ssh_passwd=$root_passwd
ssh_passwd=winner@#2023
kerberos_user=winner_spark
 
##################################
# 配置kerberos使用者: winner_spark 
# 生成keytab 檔案
##################################
config_kerberos_user() {
        echo "******** 建立winner_spark使用者例項 ********"
        /usr/bin/expect << eof
        # 設定捕獲字串後,期待回覆的超時時間
        set timeout 30
        # 登入
        spawn kadmin.local 
         
        ## 開始進連續捕獲,新增使用者
        expect  {
                "kadmin.local:"    { send "addprinc ${kerberos_user}\n"; exp_continue }
                "Enter password for principal"    { send "${ssh_passwd}\n"; exp_continue }
                "Re-enter password for principal" { send "${ssh_passwd}\n"; }
        }
       expect "kadmin.local:"    { send "quit\r";  }
eof
 
       echo "******** winner_spark使用者生成keytab檔案 ********"
        /usr/bin/expect << eof
        # 設定捕獲字串後,期待回覆的超時時間
        set timeout 30
         
        spawn kadmin.local 
         
        ## 開始進連續捕獲,生成keytab file
        expect  {
                "kadmin.local:" { send "xst -k /etc/security/keytabs/${kerberos_user}.keytab ${kerberos_user}@WINNER.COM\n";  }
        }
       expect "kadmin.local:"    { send "quit\r";  }
eof
       # modify keytab file privilege    
       chown ${kerberos_user}:hadoop /etc/security/keytabs/${kerberos_user}.keytab
       echo "********** kerberos user winner_spark add completed **********"
}
 
# 配置kerberos,並啟動
#config_krb5
 
# 配置kerberos使用者: winner_spark, 生成keytab 檔案
config_kerberos_user

相關文章