我在远程计算机上导航基于Java的CLI菜单,期望在bash脚本中,我试图从输出中提取一些东西而不离开期望会话。
我的脚本中的Expect命令是:
expect -c "
spawn ssh user@host
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
到另一个期望变量,以便在expect脚本中进一步使用。所以这是第3行,第一个字段是使用双空格分隔符。 awk等价物是:awk -F ' ' 'NR==3 {$1}'
最大的问题是,我正在使用Expect导航的环境是,如上所述,基于Java CLI的菜单,所以我不能只使用awk或其他任何可以从bash shell获得的东西。 / p>
从Java菜单中退出,处理输出然后再次进入不是一个选项,因为登录过程持续15秒所以我需要留在内部并使用expect内部命令从输出中提取我需要的内容。
答案 0 :(得分:8)
您可以使用regexp
标志直接在expect
中使用-re
。感谢Donal指出单引号和双引号问题。我已经用两种方式给出了解决方案。
我创建了一个包含以下内容的文件,
Id Name
-------------------
abcd 12 John Smith
这只是你的java程序的控制台输出。我已经在我的系统中测试了这个。即我只是用cat
模拟你的节目输出。您只需用程序命令替换cat
代码即可。简单。 :)
双引号:
#!/bin/bash
expect -c "
spawn ssh user@domain
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 user@domain
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}
。这里的括号可以防止任何变量替换。在您的输出中,我们有第二行充满连字符。然后换行。然后你的第3行内容。让我们解码使用的正则表达式。
-\r\n
将一个字面连字符和一个新行匹配在一起。这将匹配第二行中的最后一个连字符和换行符,而换行符现在又变为第三行。因此,.*?
将匹配所需的输出(即abcd 12),直到遇到与\s\s
匹配的双倍空格。
你可能想知道为什么我需要用于获得子匹配模式的括号。
通常,expect
会在expect_out(0,string)
中保存期望的整个匹配字符串,并将所有匹配/不匹配的输入缓冲到expect_out(buffer)
。每个子匹配都将保存在后续的字符串编号中,例如expect_out(1,string)
,expect_out(2,string)
等。
正如Donal指出的那样,最好使用单引号的方法,因为它看起来不那么混乱。 :)
如果是双引号,则不需要使用反斜杠转义\r
。
更新:
我已将regexp
从-\r\n(\w+\s+\w+)\s\s
更改为-\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+
与空格字符不匹配。你的输出中有一些空格,直到双倍空格。
根据您对输入字符串的要求,使用regexp会很重要。您可以根据需要自定义正则表达式。
更新版本2:
.*?
的意义是什么?如果你单独提问,我会重复你评论的内容。在正则表达式中,*
是一个贪婪的运算符,?
是我们的救星。让我们将字符串视为
Stackoverflow is already overflowing with number of users.
现在,请查看正则表达式.*flow
的效果,如下所示。
*
匹配任意数量的字符。 更确切地说,它匹配可能的最长字符串,同时仍然允许模式本身匹配。因此,由于此,模式中的.*
与字符Stackoverflow is already over
和{{匹配模式中的1}}与字符串中的文本flow
匹配。
现在,为了防止flow
仅匹配字符串.*
的第一个匹配项,我们正在向其添加flow
。它将有助于模式表现为非贪婪的方式。
现在,再次回到你的问题。如果我们使用了?
,那么它将匹配整行,因为它尽可能地匹配。这是正则表达式的常见行为。
更新版本3:
以下列方式使用您的代码。
.*\s\s
如果流程发生正常,则退出代码的值为0.否则,它将为1.这样,您可以在bash脚本中检查返回值。
请查看here以了解x=$(expect -c "
spawn ssh user@host
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;
命令。