2011-04-07 122 views
10

我寫了一個bash腳本,期望在內部連接到終端服務器並清除行。 我無法弄清楚我得到的錯誤,因爲我已經給出了所有必要的大括號。我也不理解couldn't read file "line": no such file or directory錯誤。 請幫忙。bash腳本中的期望幫助

我的腳本:

#!/bin/bash 
VAR=$(expect -c " 
spawn telnet 1.1.1.1 
expect { 
     "Password:" { send "password\r" ; exp_continue} 
     "Prompt>" { send "en\r" ; exp_continue} 
     "Password:" { send "password\r" ; exp_continue} 
     "Prompt#" {send "clea line 10\r" ; exp_continue} 
     "[confirm]" {send "Y\r" ; exp_continue} 
     "Prompt#" {send "clea line 11\r" ; exp_continue} 
     "[confirm]" {send "Y\r" ; exp_continue} 
     "Prompt#" {send "exit\r" } 
    } 
") 

echo $VAR 

其輸出:

missing close-brace 
    while executing 
"expect" 
couldn't read file "line": no such file or directory 

回答

20

第一個問題是,shell不解釋嵌套雙引號,你可能會喜歡。解決這個問題的最簡單方法是將Expect程序放在單引號中。只要Expect程序本身沒有單引號,這就足夠了。

您將遇到的下一個問題是讓單個expect命令中的所有模式和操作都將並行處理它們。實際發生的情況是,第一個Password:模式將在其看到該字符串的任何時間匹配(即使第二次使用管理員密碼)。如果兩個密碼需要不同,這將是一個問題。至少,需要將相同的模式分成不同的命令,以便它們可以按順序執行。此問題也會影響Prompt#模式,您可以在其中查找三次並希望發送三個不同的響應。

稍後,您將在發送第一個清除命令後出現錯誤。 Expect以類似於shell解釋$()``(即命令替換)的方式解釋雙引號內的方括號。你會看到類似這樣的錯誤:

invalid command name "confirm" 
    while executing 
"confirm" 
    invoked from within 
"expect { 
⋮ 

它試圖運行confirm作爲一個Tcl(或期望)命令。您可以使用大括號({})來防止Tcl做出這種解釋。此外,預期模式在默認情況下被視爲「glob」表達式(即與shell通配符一樣),所以即使您將{[confirm]}作爲模式編寫,它仍不會用於精確的字符串匹配(它將匹配任何單個字符co,n,f,i,rm)。您必須使用-ex標誌來標記模式以進行精確匹配。

解決這些問題,減少一些不必要的報價的,你可能最終得到這樣的:

#!/bin/sh 
VAR=$(expect -c ' 
    proc abort {} { 
    puts "Timeout or EOF\n" 
    exit 1 
    } 
    spawn telnet 1.1.1.1 
    expect { 
    Password:  { send "password1\r" } 
    default   abort 
    } 
    expect { 
    Prompt>   { send "en\r"; exp_continue } 
    Password:  { send "password2\r" } 
    default   abort 
    } 
    expect { 
    Prompt#   { send "clea line 10\r"; exp_continue } 
    -ex {[confirm]} { send "Y\r" } 
    default   abort 
    } 
    expect { 
    Prompt#   { send "clea line 11\r"; exp_continue } 
    -ex {[confirm]} { send "Y\r" } 
    default   abort 
    } 
    expect { 
    Prompt#   { send "exit\r"; exp_continue } 
    timeout   abort 
    eof 
    } 
    puts "Finished OK\n" 
') 

echo "$VAR" 
+0

感謝您的詳細解釋。這真的幫助我解決我的問題,我做了兩個更多的更改,我將在單獨回答相同的帖子時詳細說明。 – Pkp 2011-04-07 18:45:53

1

的問題是,在預期腳本雙引號的期望腳本的結尾處理。嘗試用雙引號混合單引號:

#!/bin/bash 
VAR=$(expect -c ' 
spawn telnet 1.1.1.1 
expect { 
"Password:" { send "password\r" ; exp_continue} 
"Prompt>" { send "en\r" ; exp_continue} 
"Password:" { send "password\r" ; exp_continue} 
"Prompt#" {send "clea line 10\r" ; exp_continue} 
"[confirm]" {send "Y\r" ; exp_continue} 
"Prompt#" {send "clea line 11\r" ; exp_continue} 
"[confirm]" {send "Y\r" ; exp_continue} 
"Prompt#" {send "exit\r" } 
} 
') 
1

@David有正確的答案。

有關您期望的腳本樣式的註釋:您的expect/send命令是線性的,所以看起來令人困惑的是有一個expect塊和一堆exp_continue語句。這將是更直接寫這個:

VAR=$(expect -c ' 
    spawn telnet 1.1.1.1 
    expect "Password:" 
    send "password\r" 
    expect "Prompt>" 
    send "en\r" 
    expect "Password:" 
    send "password\r" 
    expect "Prompt#" 
    send "clea line 10\r" 
    expect "[confirm]" 
    send "Y\r" 
    expect "Prompt#" 
    send "clea line 11\r" 
    expect "[confirm]" 
    send "Y\r" 
    expect "Prompt#" 
    send "exit\r" 
    expect eof 
') 
3

@克里斯:我納入你建議的修改,現在我的代碼工作。

但是我不得不做出兩個如下所述的變化:

1]你提到的單引號阻止參數替換。例如,我不能寫$IP來代替1.1.1.1。因此,爲了解決這個問題,我刪除了單引號,並用雙引號替換。正如你提到的嵌套雙引號不是由bash解釋的,這是真的。因此,我重寫了內雙引號

send \"password1\r\" 

即內部的雙引號前添加反斜線。這糾正了參數替換的問題。

2]即使我在單個expect命令中放置了兩個/三個操作,但它們並行運行後,我仍面臨一些問題。所以採取你的建議,我把每個行動放在單獨的expect命令中。類似於

expect { 
    Prompt>   { send "en\r"; exp_continue } 
} 
expect { 
    Password:  { send "password2\r" } 
}