期望:从输出中提取特定字符串

lin*_*bie 2 tcl expect

我正在远程机器上导航基于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###
Run Code Online (Sandbox Code Playgroud)

期望输出是:

Id       Name
-------------------
abcd 12  John Smith
Run Code Online (Sandbox Code Playgroud)

我想abcd 12从上面的输出中提取另一个期望变量,以便在expect脚本中进一步使用.所以这是第3行,第一个字段是使用双空格分隔符.awk等价物将是:awk -F ' ' 'NR==3 {$1}'

最大的问题是,我正在使用Expect导航的环境是,如上所述,基于Java CLI的菜单,所以我不能只使用awk或其他任何可从bash shell获得的东西.

从Java菜单中退出,处理输出然后再次进入不是一个选项,因为登录过程持续15秒,所以我需要留在内部并使用expect内部命令从输出中提取我需要的内容.

Din*_*esh 8

您可以使用regexpexpect本身直接与使用的-re标志.感谢Donal指出单引号和双引号问题.我用两种方式给出了解决方案.

我创建了一个文件,内容如下,

Id       Name
-------------------
abcd 12  John Smith
Run Code Online (Sandbox Code Playgroud)

这只是你的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\"
"
Run Code Online (Sandbox Code Playgroud)

单引号:

#!/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"
'
Run Code Online (Sandbox Code Playgroud)

如你所见,我已经习惯了{-\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.
Run Code Online (Sandbox Code Playgroud)

现在,请看下正则表达式的效果.*flow如下.

在此输入图像描述

*匹配任意数量的字符.更确切地说,它匹配可能的最长字符串,同时仍然允许模式本身匹配. 因此,由于这个原因,.*在匹配的模式中,字符 Stackoverflow is already overflow模式匹配flow字符串中的文本.

现在,为了防止.*仅匹配第一次出现的字符串flow,我们正在添加?它.它将有助于模式表现为非贪婪的方式.

在此输入图像描述

现在,再次回到你的问题.如果我们已经使用过.*\s\s,那么它将匹配整行,因为它试图尽可能地匹配.这是正则表达式的常见行为.

更新版本3:

以下列方式使用您的代码.

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;
Run Code Online (Sandbox Code Playgroud)

如果流程发生正常,则退出代码的值为0.否则,它将具有1.通过这种方式,您可以检查bash脚本中的返回值.

看看这里了解info exists命令.