最近在做一些系統運維的事,所以扔了好久的shell又撿了起來,什么變量定義、函數之類的。
其中常用的操作包括數據庫的導出、導入,開發環境編譯打包之后上傳文件到服務器,在服務器上停機、再啟動等等操作。這些工作的特點就是常規的、日程化的,所以可以抽取出來寫一個腳本做成一鍵自動執行(大概是受了微服務理念的影響,最近做什么事都想著自動化,消除人為因素)。但這里碰到個問題,許多操作是需要人工介入的,比如 scp、ssh、psql、pg_dump(這兩個命令是用于 PostgreSQL 數據庫導入導出的,其它類型的數據庫也類似),都需要人工輸入 password 才能繼續執行命令。解決這個問題就可以用 Expect ,實現自動和交互式任務進行通信,而無需人的干預。通過它可以將交互過程寫在一個腳本上,使之自動化完成!
可以在Expect的官網下載安裝,我本機用的是 mac 的 homebrew 方式:
brew 搜索 expect
brew search expect
brew 安裝 expect
brew install expect
安裝完成后看下 Expect 的用法,常用的有3個命令:
expect:從進程接收字符串
send:用于向進程發送字符串
spawn:啟動新的進程
下面是一個簡單的自動執行 scp 命令的例子,新建一個文件 scp.exp ,內容如下:
#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]
spawn scp $src_file $username@$host:$dest_file
expect {
"*password:"
{
send "$password\n"
}
}
第1行的意思是告訴操作系統腳本里的代碼使用那一個shell來執行,#!后面跟著的就是 expect 的二進制文件路徑,所以必須將它放在文件的第1行。
第2行 set timeout 是用于設置執行命令的超時時間,單位是秒,-1表示永不超時。這里的 set 語句就是 shell 里設置變量的意思。
第3到7行也是設置變量值,不同的是先定義了一個變量,然后變量的值是從文件入參中獲取的。
expect 腳本可以接受從 bash 傳遞過來的參數,用[lindex $argv n]獲得,n從0開始,分別表示第1個,第2個,第3個....參數
第8行的 spawn 是 expect 的內部命令,這里給 scp 的運行進程加個殼,用來傳遞交互指令。
第9行的 expect 也是 expect 的內部命令,后面接的大括號包含的語句塊,其中 "password:"的意思是判斷第8行的 spawn 執行后的輸出結果里是否包含以password:結尾的字符串,前面的是正則表達式,表示匹配任意字符串。如果有則立即返回,否則就等待一段時間后返回,這里等待時長就是前面設置的10秒 。
第12行的 send 同樣是內部命令,意思是執行交互動作,相當于人工輸入密碼,密碼就是上面定義的變量 password ,也即文件執行時的第3個參數的值。
最后將該文件保存,并賦予執行的權限:
chmod +x scp.exp
這樣執行
./scp.expect 主機地址 用戶名 密碼 源文件路徑 目標文件路徑
即可自動執行上傳文件功能,無需人工輸入密碼。
由此類推可以將原先需要人工介入的命令操作嵌入到 shell 腳本中,實現命令操作的自動化。