expect安裝和使用

   

  Expect是一個咱們常在shell交互時經常使用到的工具,它主要由expect-send組成。Expect是等待輸出內容中的特定字符。而後由send發送特定的相應。Expect的工做流程相似於:小明和小紅說:hello,小紅髮現小明說的是hello,而後就回復小明hi。而後小明說:你好,我是小明。小紅髮現小明說的是」你好,我是XX「,就回復」你好,我是小紅「。html

本文主要內容: 1.安裝expect    2 expect的一些基本命令選項   3 expect腳本shell

1.  安裝expectsegmentfault

  1.1 yum 安裝
windows

  yum安裝就比較簡單了,直接運行yum install expect就能夠了. bash

yum  install expect

   1.2 源碼安裝服務器

  源碼安裝前咱們須要安裝unzip和gcc ssh

yum  install  unzip gcc -y

   源碼安裝咱們須要下載兩個源碼包。tcl源碼包和expect源碼包。 工具

  下載tcl源碼包post

cd /tmp &&wget  http://core.tcl.tk/tcl/zip/release/tcl.zip

   下載expect源碼包字體

wget https://jaist.dl.sourceforge.net/project/expect/Expect/5.45.3/expect5.45.3.tar.gz

  咱們須要先編譯安裝tcl,由於expect包依賴於tcl。

  解壓壓縮包並編譯安裝tcl 

unzip tcl.zip && cd ./tcl/unix ./configure && make && make install

  解壓壓縮包並編譯安裝expect.

cd /tmp && tar -xzvf expect5.45.3.tar.gz && cd expect5.45.3/ ./configure && make && make install

  檢查是否安裝好(顯示安裝好的版本號就是已經安裝好了)並建立軟連接。

expect -v [root@localhost shell]# expect -v expect version 5.45.3
[root@localhost shell]# ln -s /usr/local/bin/expect  /usr/bin/expect

2.expect經常使用的參數選項

  2.1  使用 -c 選項:在命令行運行expect 腳本。

  示例:

[root@localhost shell]# expect -c 'expect "hi expect" {send "hi shell\n"}' hi expect hi shell [root@localhost shell]# 

  解釋下:這個的意思就是當咱們輸入了"hi expect"後,系統輸出"hi shell"表示迴應,在"hi shell"後加"\n"是爲了讓顯示更爲直觀。

  注意一點就是咱們在輸入完"hi expect"後要按換行鍵纔會出來"hi shell".

  2.2 使用 -d 選項:顯示調試信息。

  示例腳本:

[root@localhost shell]# cat ssh.exp #!/usr/bin/expect -d set timeout 30 spawn ssh-copy-id 192.168.123.218 expect { "*yes/no" {send "yes\r"; exp_continue} "password:" {send "123456\r"} } expect eof

  當我運行它的時候,顯示的信息(主要信息是加粗字體):

expect version 5.45 argv[0] = /usr/bin/expect  argv[1] = -d  argv[2] = ./ssh.exp set argc 0 set argv0 "./ssh.exp" set argv "" executing commands from command file ./ssh.exp spawn ssh-copy-id 192.168.123.218 parent: waiting for sync byte parent: telling child to go ahead parent: now unsynchronized from child spawn: returns {130244} expect: does "" (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" expect: does "/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"\r\n" (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no The authenticity of host '192.168.123.218 (192.168.123.218)' can't be established.
ECDSA key fingerprint is SHA256:Qh+4R5mpwlU6kK3bf0k53ngm+WpKKnfvL1ZJo+YM3ic. ECDSA key fingerprint is MD5:d2:76:6d:33:17:e1:51:83:13:aa:10:ce:f7:1f:9f:32. Are you sure you want to continue connecting (yes/no)? expect: does "/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"\r\nThe authenticity of host '192.168.123.218 (192.168.123.218)' can't be established.\r\nECDSA key fingerprint is SHA256:Qh+4R5mpwlU6kK3bf0k53ngm+WpKKnfvL1ZJo+YM3ic.\r\nECDSA key fingerprint is MD5:d2:76:6d:33:17:e1:51:83:13:aa:10:ce:f7:1f:9f:32.\r\nAre you sure you want to continue connecting (yes/no)? " (spawn_id exp6) match glob pattern "*yes/no"? yes expect: set expect_out(0,string) "/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"\r\nThe authenticity of host '192.168.123.218 (192.168.123.218)' can't be established.\r\nECDSA key fingerprint is SHA256:Qh+4R5mpwlU6kK3bf0k53ngm+WpKKnfvL1ZJo+YM3ic.\r\nECDSA key fingerprint is MD5:d2:76:6d:33:17:e1:51:83:13:aa:10:ce:f7:1f:9f:32.\r\nAre you sure you want to continue connecting (yes/no" expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) "/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"\r\nThe authenticity of host '192.168.123.218 (192.168.123.218)' can't be established.\r\nECDSA key fingerprint is SHA256:Qh+4R5mpwlU6kK3bf0k53ngm+WpKKnfvL1ZJo+YM3ic.\r\nECDSA key fingerprint is MD5:d2:76:6d:33:17:e1:51:83:13:aa:10:ce:f7:1f:9f:32.\r\nAre you sure you want to continue connecting (yes/no" send: sending "yes\r" to { exp6 } expect: continuing expect expect: does ")? " (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no yes expect: does ")? yes\r\n" (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed expect: does ")? yes\r\n/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed\r\n" (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys expect: does ")? yes\r\n/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed\r\n/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys\r\n" (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? no root@192.168.123.218's password:  expect: does ")? yes\r\n/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed\r\n/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys\r\nroot@192.168.123.218's password: " (spawn_id exp6) match glob pattern "*yes/no"? no "password:"? yes expect: set expect_out(0,string) "password:" expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) ")? yes\r\n/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed\r\n/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys\r\nroot@192.168.123.218's password:" send: sending "123456\r" to { exp6 } Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.123.218'" and check to make sure that only the key(s) you wanted were added. expect: read eof expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) " \r\n\r\nNumber of key(s) added: 1\r\n\r\nNow try logging into the machine, with: "ssh '192.168.123.218'"\r\nand check to make sure that only the key(s) you wanted were added.\r\n\r\n"

 還有一些其餘參數,可是我以爲對於我用處不大,因此沒有在此記錄。

3.expect腳本示例

  簡單在這記錄下下面會用到的一些命令

  set timeout           #設置超時時間,默認超時時間10s.

  spawn shell command   # spawn後面接的是咱們要執行的shell命令

  expect "hi"        #匹配輸出內容「hi」

  {send 「hello\r」}                    # 匹配到內容''hi"後輸出「hello」,「\r」是表明是返回字符

  interact             #執行完成後保持交互狀態,把控制權交給控制檯,這個時候就能夠手工操做了。若是沒有這一句登陸完成後會退出,而不是留在遠程終端上。若是你只是登陸過去執行一段命令就退出,可改成[expect eof] 

  3.1 簡單更改密碼腳本

[root@localhost shell]# cat password.exp #!/usr/bin/expect -d #"#!/usr/bin/expect"這一行告訴操做系統腳本里的代碼使用那一個shell來執行。 -d 啓用調試模式(可加可不加)。
set timeout 30              #設置超時時間爲30s spawn
passwd user5            #spawn是進入expect環境後才能夠執行的expect內部命令,若是沒有裝expect或者直接在默認的SHELL下執行是找不到spawn命令的。因此不要用 「which spawn「之類的命令去找spawn命令。比如windows裏的dir就是一個內部命令,這個命令由shell自帶,你沒法找到一個dir.com 或 dir.exe 的可執行文件。它主要的功能是給ssh運行進程加個殼,用來傳遞交互指令。 expect "New password:" {send "123456\r" } #這個命令的意思是判斷上次輸出結果裏是否包含「New password:」的字符串,若是有則當即返回"123456","\r"表明是返回字符,不然就等待一段時間後返回,這裏等待時長就是前面設置的30秒 。 expect "new password:" {send "123456\r"} #在日常咱們設置密碼的時候會讓我輸入一次後再輸入一次進行確認,這個是匹配第二次輸出,而後再次輸入密碼。 expect eof                #表示讀取到文件結束符

  3.2登錄遠程服務器並停留在遠程服務器上

[root@localhost shell]# cat login.exp #!/usr/bin/expect spawn ssh 192.168.123.218 #ssh 遠程登錄 expect { "*yes/no" {send "yes\r";exp_continue} #匹配輸出內容,返回內容,exp_continue表示繼續執行下一步 "*password" {send "123456\r"} } interact #執行完成後保持交互狀態,把控制權交給控制檯,這個時候就能夠手工操做了。若是沒有這一句登陸完成後會退出,而不是留在遠程終端上。若是你只是登陸過去執行一段命令就退出,可改成[expect eof]

  3.3傳輸參數執行登錄 

[root@localhost shell]# cat login2.exp #!/usr/bin/expect set ip [lindex $argv 0] #這條命令是將變量ip的值設置爲傳入進來的第一個參數。[lindex $argv 0]表示的就是第一個參數的值 set port [lindex $argv 1] #這條命令是將變量port的值設置爲傳入進來的第二個參數。[lindex $argv 1]表示的就是第二個參數的值 set passwd "123456" spawn ssh $ip -p$port #使用變量,這裏使用的方法跟shell腳本同樣 expect { "yes/no" {send "yes\r";exp_continue} "password:" {send "$passwd\r"} } interact [root@localhost shell]# ./login2.exp  192.168.123.218 22 #多個參數直接以空格間隔,第一個參數:192.168.123.218 第二個參數22

   3.4在shell腳本中使用expect

    3.4.1經過添加expect腳本文件(建議這種)   

      實現的功能:輸入ip(也就是咱們傳入的參數),並登錄到這個ip,並保持交互狀態(interact

      login.sh腳本內容(shell)

[root@localhost shell]# cat login.sh #!/bin/bash read -p "please input you ip:" -t30 remote_ip #獲取登錄ip內容 echo "$remote_ip" ./login.exp $remote_ip  #運行expect腳本 傳入參數

       login.exp腳本內容(expect)

[root@localhost shell]# cat login.exp #!/usr/bin/expect set ip [lindex $argv 0] #將參數值傳遞給變量ip spawn ssh $ip      #登錄ip expect { "*yes/no" {send "yes\r";exp_continue} #匹配登錄信息,返回'yes' "*password" {send "123456\r"} #匹配輸出信息,返回密碼 } interact #登錄成功後保持交互狀態,把控制權交給控制檯

    3.4.2在shell腳本直接寫入expect命令

#!/bin/bash read -p "please input you ip:" -t30 remote_ip #獲取登錄ip內容 echo "$remote_ip" expect -d <<EOF spawn ssh $remote_ip expect { "*yes/no" {send "yes\r";exp_continue} "*password:" {send "Xuansiwei123!\r"} } exit expect eof; EOF

    3.4.3 expect匹配不一樣狀況(有密鑰文件則退出,沒有則添加)  

sshkey.exp

#!/usr/bin/expect -d 
spawn ssh-keygen
expect {
".ssh/id_rsa" {send "\r";exp_continue}
"Overwrite (y/n)?" exit    #判斷是否已經有密鑰文件,有則退出,沒有就進行添加。
"Enter passphrase" {send "\r";exp_continue}
"Enter same passphrase again:" {send "\r"}
}
expect eof

 

  3.5批量分發公鑰到遠程主機

  批量分發我主要有三個文件,第一個是ip.txt(用來儲存ip和密碼的,ip和密碼直接以":"間隔,示例:192.168.123.12:123456),第二個文件是add.sh(包含讀取ip.txt和批量添加的腳本),第三個文件是 ssh_copy.exp(用來處理交互的腳本)

  ip.txt文件內容

#ip password 192.168.123.110:123456
192.168.123.111:123@456!

  這裏注意下我第二行的ip的密碼的最後一位是「!」,它在我shell腳本中的取出密碼步驟也給我形成了一點麻煩,直接echo "$i"是報錯的,我後面換成了echo "${i}",這樣就不會報錯了。

  add.sh(shell腳本)

#!/bin/bash IP_file='/root/shell/ip.txt'
if [ -e  "$IP_file" ]          #檢查ip.txt文件是否存在, then
    echo -e "\033[1;32;40m IP file is exist \033[0m" 
else 
    echo -e "\033[1;31;40m IP file is not exist \033[0m" exit 2
fi
for i in $(cat ${IP_file}) do IP=$(echo "${i}" |awk -F":" '{print $1}') #將ip.txt每行的ip值獲取 PW=$(echo "${i}" |awk -F":" '{print $2}')#將ip.txt每行的ip值獲取
  ./ssh_copy.exp $IP $PW 
  if [ $? -eq 0 ] #判斷expect腳本是否執行成功
  then

    echo "$IP add is ok "
  else
    echo "$IP add faile"
  fi
done

  在上面的shell腳本咱們還能夠再加一個驗證是否添加成功了,經過驗證是否能夠直接ssh登陸來判斷是否添加成功。

  ssh_copy.exp(expect腳本)

#!/usr/bin/expect #調試的時候能夠加個-d參數,便於查看咱們的哪裏步驟出現了錯誤。 set IP [lindex $argv 0 ] set PW [lindex $argv 1 ] spawn ssh-copy-id $IP expect { "yes/no" {send "yes\r";exp_continue} "password:" {send "$PW\r"} } expect eof

 

ssh和ssh-copy-id以及批量多機無密碼登錄詳解

這篇文章參考如下大佬的文章。

https://www.cnblogs.com/lixigang/articles/4849527.html

https://segmentfault.com/a/1190000002564816

相關文章
相關標籤/搜索