2014-11-23 34 views
0

我在遠程計算機上瀏覽基於Java的CLI菜單,期望在bash腳本中運行,我試圖在不離開期望會話的情況下從輸出中提取某些內容。期望:從輸出中提取特定的字符串

期待在我的腳本命令是:

expect -c " 
spawn ssh [email protected] 
expect \"#\" 
send \"java cli menu command here\r\" 
expect \"java cli prompt\" 
send \"java menu command\" 
" 
###I want to extract a specific string from the above output### 

期望輸出爲:

Id  Name 
------------------- 
abcd 12 John Smith 

我想從上面的輸出中提取abcd 12到另一所期望的期望腳本中進一步使用變量。所以這是第三行,第一個字段是使用雙空格分隔符。 awk相當於:awk -F ' ' 'NR==3 {$1}'

最大的問題是,我正在使用Expect進行導航的環境,正如我上面所述,基於Java CLI的菜單,所以我不能只使用awk或其他任何可以從bash shell獲得。

從Java菜單中退出,處理輸出然後重新登錄不是一個選項,因爲登錄過程持續15秒,所以我需要留在裏面並使用expect內部命令從輸出中提取我需要的內容。

+0

問題的核心在於你試圖將期望腳本放入雙引號的shell文本中。這會迫使你使用_Lots_的反斜槓引用。雖然您可以這樣做,但將期望腳本放在自己的文件中(例如'mydostuff.exp')會使一切變得簡單。然後你可以用'expect mydostuff.exp'運行它... – 2014-11-23 23:21:47

回答

4

您可以使用regexpexpect本身直接使用-re標誌。感謝Donal指出單引號和雙引號問題。我已經用兩種方法給出瞭解決方案。

我已經創建了內容的文件,如下所示,

Id  Name 
------------------- 
abcd 12 John Smith 

這不過是你的java程序的控制檯輸出。我已經在我的系統中對此進行了測試。即我只是用cat來模擬你的程序輸出。您只需使用程序命令替換cat代碼即可。簡單。 :)

雙引號:

#!/bin/bash 
expect -c " 
spawn ssh [email protected] 
expect \"password\" 
send \"mypassword\r\" 
expect {\\\$} { puts matched_literal_dollar_sign} 
send \"cat input_file\r\"; # Replace this code with your java program commands 
expect -re {-\r\n(.*?)\s\s} 
set output \$expect_out(1,string) 
#puts \$expect_out(1,string) 
puts \"Result : \$output\" 
" 

單引號:

#!/bin/bash 
expect -c ' 
spawn ssh [email protected] 
expect "password" 
send "mypasswordhere\r" 
expect "\\\$" { puts matched_literal_dollar_sign} 
send "cat input_file\r"; # Replace this code with your java program commands 
expect -re {-\r\n(.*?)\s\s} 
set output $expect_out(1,string) 
#puts $expect_out(1,string) 
puts "Result : $output" 
' 

正如你所看到的,我已經使用{-\r\n(.*?)\s\s}。這裏的大括號可以防止任何變量替換。在你的輸出中,我們有一個帶有連字符的第二行。然後換行。然後你的第三行內容。讓我們解碼使用的正則表達式。

-\r\n將匹配一個文字連字符和一個新行在一起。這將匹配第二行中的最後一個連字符和換行,然後將其轉換爲第三行。因此,.*?將匹配所需的輸出(即abcd 12),直到它遇到與\s\s匹配的雙倍空間。

您可能想知道爲什麼我需要使用括號來獲得子匹配模式。

一般來說,expect會將預期的整個匹配字符串保存在expect_out(0,string)中,並將所有匹配/不匹配的輸入緩衝到expect_out(buffer)。每個子匹配將被保存在字符串的後續編號中,如expect_out(1,string),expect_out(2,string)等等。

enter image description here

正如多納爾指出的那樣,最好使用單引號的方法,因爲它看起來不太凌亂。 :)

如果是雙引號,則不需要用反斜槓來轉義\r

更新:

我從-\r\n(\w+\s+\w+)\s\s改變regexp-\r\n(.*?)\s\s

用這種方式 - 您的要求 - 如match any number of letters and single spaces until you encounter first occurrence of double spaces in the output

現在,讓我們來你的問題。你提到你已經試過-\r\n(\w+)\s\s。但是,\w+這裏存在問題。記住\w+將不匹配空格字符。你的輸出中有一些空格,直到雙空格。

正則表達式的使用將根據您對要匹配的輸入字符串的要求而定。您可以根據您的需要自定義正則表達式。

更新版2:

什麼是.*?意義。如果您另外提問,我將重複您所評論的內容。在正則表達式中,*是一個貪婪的運算符,?是我們的救命。讓我們考慮字符串作爲

Stackoverflow is already overflowing with number of users. 

現在,看到正則表達式.*flow如下的效果。

enter image description here

*匹配任何數目的字符。 更確切地說,它匹配的字符串,最長的可能,同時仍允許模式本身相匹配。因此,由於這個原因,.*在模式匹配的字符Stackoverflow is already over和模式flow匹配的字符串文本flow

現在,爲了防止.*僅匹配字符串flow的第一個匹配項,我們將?添加到它。這將有助於該模式表現爲非貪婪的態度。

enter image description here

現在,再來回到你的問題。如果我們使用.*\s\s,那麼它將整條生產線,因爲它正試圖儘可能地匹配匹配。這是正則表達式的共同行爲。

更新版本3:

在下列方式你的代碼。

x=$(expect -c " 
spawn ssh [email protected] 
expect \"password\" 
send \"password\r\" 
expect {\\\$} { puts matched_literal_dollar_sign} 
send \"cat input\r\" 
expect -re {-\r\n(.*?)\s\s} 
if {![info exists expect_out(1,string)]} { 
     puts \"Match did not happen :(\" 
     exit 1 
} 
set output \$expect_out(1,string) 
#puts \$expect_out(1,string) 
puts \"Result : \$output\" 
") 
y=$? 

# $x now contains the output from the 'expect' command, and $y contains the 
# exit status 
echo $x 
echo $y; 

如果流量發生不當,則退出代碼將價值爲0。否則,將有1.這樣一來,您就可以在bash腳本的返回值。

看看here瞭解info exists命令。

+0

你需要反斜槓引用'$',否則unix shell會破壞它;使用'expect -c「...」「只是增加了所有事情的煩人混亂層次。 '\ r's可能還需要一個額外的反斜槓。 – 2014-11-23 23:23:28

+0

@linux_newbie:我已經更新了我的答案。請檢查。 – Dinesh 2014-11-24 12:39:38

+0

@DonalFellows:非常感謝Donal幫助我瞭解更多信息。我已更正以及測試我的答案。讓我知道任何其他變化。 – Dinesh 2014-11-24 12:40:43

相關問題