expect 介紹
借助 expect 處理交互的命令,可以將交互過程如 ssh 登錄, ftp 登錄等寫在一個腳本上,使之自動化完成。尤其適用於需要對多台服務器執行相同操作的環境中,可以大大提高系統管理員的工作效率。
expect 安裝
[root@ansible ssh]# rpm -qa | grep expect
expect-5.45-14.el7_1.x86_64
[root@ansible ssh]# yum -y install expect
expect 語法
expect [選項] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
選項
-c:從命令行執行expect腳本,默認expect是交互地執行的
示例:expect -c 'expect "\n" {send "pressed enter\n"}'
-d:輸出調試信息
示例:expect -d ssh.exp
expect中的相關命令
spawn:啟動新的進程
send:向進程發送字符串
expect:從進程接收字符串
interact:允許用戶交互
exp_continue 匹配多個字符串時在執行動作后加此命令
expect最常用的語法(tcl語言:模式-動作)
單一分支模式的語法:
expect "hi" { send "You said hi\n" } 匹配到 hi 后,會輸出"you said hi",並換行
多分支模式的語法:
expect "hi" { send "You said hi\n" } \ "hehe" { send “Hehe yourself\n" } \ "bye" { send "Goodbye\n" }
匹配 hi, hehe, bye 中的任意字符串時, 發送相應字符串。等同於:
expect { "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n" } "bye" { send "Goodbye\n" } }
自動拷貝文件到遠程主機
執行 expect 不能以 `bash file` 的方式來執行 (開啟一個子shell進程)
必須通過 `chmod +x file ; ./file` 這樣的方式 (不會開啟子shell進程, 只在當前shell環境中執行)
expect 如果只交互一次如拷貝文件 結尾就使用 `expect eof`
如果需要連續交互如登錄遠程主機執行各種命令結尾就需使用 `interact`
示例一
1.安裝expect 系統默認沒有此命令
yum install expect
2.創建配置文件
[root@ansible ssh]# vi hosts
192.168.31.134 root root
192.168.31.135 root root
192.168.31.136 root root
3.編寫腳本
[root@ansible ssh]# ls
copykey.sh hosts
[root@ansible ssh]# vi copykey.sh
#!/bin/bash
if [ ! -f ~/.ssh/id_rsa ];then
ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
else
echo "id_rsa has created ..."
fi
#分發到各個節點
while read line
do
user=`echo $line | cut -d " " -f 2`
ip=`echo $line | cut -d " " -f 1`
passwd=`echo $line | cut -d " " -f 3`
expect <<EOF
set timeout 10
spawn ssh-copy-id $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$passwd\n" }
}
expect "password" { send "$passwd\n" }
EOF
done < hosts
4.給腳本執行權限
chmod +x copykey.sh
5.執行腳本
./copykey.sh
讀取配置文件自動執行ssh
示例二
#!/usr/bin/expect
spawn scp /etc/fstab root@192.168.33.129:/root
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "root\n" }
}
expect eof
[root@centos7 ~]# bash one.expect
one.expect: line 2: spawn: command not found
couldn't read file "{": no such file or directory
one.expect: line 4: yes/no: No such file or directory
one.expect: line 4: exp_continue: command not found
one.expect: line 5: password: command not found
one.expect: line 6: syntax error near unexpected token `}'
one.expect: line 6: `}'
[root@centos7 ~]# ./one.expect
spawn scp /etc/fstab root@192.168.33.129:/root
The authenticity of host '192.168.33.129 (192.168.33.129)' can't be established.
RSA key fingerprint is SHA256:FzQU22CgZBnSbmZAuoypliidxPK9PsOFjJwcYUZWk5E.
RSA key fingerprint is MD5:a8:2b:51:c3:dc:09:65:89:78:d2:d5:e0:9f:e9:30:1a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.33.129' (RSA) to the list of known hosts.
root@192.168.33.129's password:
fstab
示例三
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd haha\n" }
expect "]#" { send "echo aaa|passwd --stdin haha\n" }
send "exit\n" expect eof
#./ssh4.exp 192.168.8.100 root aa
執行多條命令
示例四
#!/bin/bash
ip=$1
user=$2
password=$3
expect <<EOF
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo rrr|passwd --stdin hehe\n" }
expect "]#" { send "exit\n" } expect eof
EOF
#./ssh5.sh 192.168.8.100 root aaa
shell調用expect