【问题标题】:Expect in Bash script: expect_out not printing out bufferBash 脚本中的期望:expect_out 没有打印出缓冲区
【发布时间】:2020-06-13 03:28:50
【问题描述】:

我试图通过登录交换机来捕获“dir”命令的输出,但我无法这样做。我在 Bash 中使用 Expect。我正在使用 expect_out 在缓冲区中捕获该命令的输出并将其打印出来。实际上我想捕获输出并对其执行一些操作。

脚本:

#!/bin/bash
expect -c "
spawn telnet 1.1.1.1 2000
sleep 1
send \"\r\"
send \"\r\"
expect {
Prompt> { send \"dir\r\"  }
}
set output $expect_out(buffer)
"
echo "$output"

输出:

spawn telnet 1.1.1.1 2000
Trying 1.1.1.1...
Connected to 1.1.1.1 (1.1.1.1).
Escape character is '^]'.




Prompt>

Prompt>

显示这些提示后,脚本就退出了。我该如何解决这个问题?

拆分后,我可以使用参数替换以及单引号。现在我面临不同的错误。

脚本:

expect -c "
spawn telnet $IP $PORT1
sleep 1
send \"\r\"
send \"\r\"
"
expect -c '
expect {
Prompt> { send \"dir\r\" }
set output $expect_out(buffer)
puts "$output"
}
'

输出:

spawn telnet 172.23.149.139 2033
can't read "expect_out(buffer)": no such variable
while executing
"expect {
Prompt> { send \"dir\r\" }
set output $expect_out(buffer)
puts "$output"
}
"

我根据建议将其更改为。但我仍然面临错误。

脚本:

output=$(expect -c '
spawn telnet '"$IP $PORT1"'
sleep 1
send '"\r"'
send '"\r"'

expect Prompt> { send '"dir\r"'  }
expect '"\n"'
expect -indices Prompt>
puts '"[string range $expect_out(buffer) 0 [expr $expect_out(0,end) - 1]]"'

')

echo "======="
echo "$output"
echo "======="

输出:

syntax error in expression "(0,end) - 1"
    while executing
"expr (0,end) - 1"
    invoked from within
"string range (buffer) 0 [expr (0,end) - 1]"
    invoked from within
"puts [string range (buffer) 0 [expr (0,end) - 1]]"

=======
spawn telnet 1.1.1.1 2000
Trying 1.1.1.1...
Connected to 1.1.1.1 (1.1.1.1).
Escape character is '^]'.




Prompt>

Prompt>
=======

因此为了规避错误,我改了行

puts '"[string range $expect_out(buffer) 0 [expr $expect_out(0,end) - 1]]"'

puts '"$expect_out(buffer)"'

然后我没有收到任何错误,但dir 的输出也没有被打印出来。比如:

Prompt>

Prompt> (buffer)

【问题讨论】:

  • 格式提示:您应该为您的代码和输出块使用正确的代码格式(而不是在每行末尾使用两个尾随空格来强制换行/分段)。除了更健壮(它可以防止对代码的 Markdown 解释)之外,它通常更容易做到,因为您只需突出显示代码并按 Control-K。请参阅Editing Help(位于编辑文本区域右上角正上方的橙色问号)。

标签: bash expect


【解决方案1】:

您的第二个“拆分”Expect 程序无法访问生成的 telnet 进程。当您像那样拆分它们时,您使它们独立(一个无法访问另一个的变量或状态;实际上,当第二个已启动第一个及其 telnet 进程时,没有不再存在)。


shell 将自动连接任何字符串(不被未引用/未转义的空格分隔),而不考虑它们使用的引号类型(如果有的话)。这意味着您可以开始将 Expect 程序的第一部分放在单引号中,切换到双引号进行参数替换,然后在程序的其余部分返回单引号(以避免必须转义任何 "$\`发生在您的 Expect 代码中)。

expect -c '
spawn telnet '"$HOST $PORT"'
sleep 1
⋮ (rest of Expect program)
'

它使用单引号来保护大部分程序,但切换回双引号以让 shell 将其 HOST 和 IP 参数替换为 Expect 程序的文本。


接下来,启动expect 的shell 不能访问Expect 程序中设置的变量。从子进程收集输出的正常方法是让它写入 stdout 或 stderr 并让 shell 通过命令替换 ($()) 收集输出。

在 Tcl(和 Expect)中,您可以使用 puts 将字符串发送到标准输出。但是,默认情况下,Expect 还将向标准输出发送正常的“交互”输出(它从任何衍生命令接收到的内容以及发送给它们的内容;即,如果您手动运行生成的命令,您会看到什么)。您可以使用 log_user 0 禁用此默认日志记录。

你可以这样写你的程序:

#!/bin/sh
output=$(expect -c '
# suppress the display of the process interaction
log_user 0

spawn telnet '"$HOST $PORT"'
sleep 1
send "\r"
send "\r"
# after a prompt, send the interesting command
expect Prompt> { send "dir\r"  }
# eat the \n the remote end sent after we sent our \r
expect "\n"
# wait for the next prompt, saving its position in expect_out(buffer)
expect -indices Prompt>

# output what came after the command and before the next prompt
# (i.e. the output of the "dir" command)
puts [string range $expect_out(buffer) \
                   0 [expr $expect_out(0,start) - 1]]
')
echo "======="
echo "$output"
echo "======="

【讨论】:

  • 感谢您的快速回复,这帮助我纠正了一些错误。我仍然面临一些错误。请帮忙。我用新的错误编辑了我的问题。
  • 在您更新的代码中,您似乎已将最后一条语句从单引号中移出并放入双引号部分。关于您为什么尝试这样做,我最好的猜测是您认为 shell 需要替换 $expect_out(buffer)。该表达式是 Expect 程序的一部分。 shell 不会对它做任何有用的事情(它可能只是在 Expect 程序中扩展为 (buffer),这只是 Tcl 中的文字字符串)。是否有问题促使您重写最后一条语句?我测试了我发布的内容;我写的时候它对我有用。
【解决方案2】:

因为您的 Expect 脚本用双引号括起来,所以 shell 将 $expect_out 扩展为一个空字符串。将期望脚本的主体放在单引号中。

当您在 Expect 中设置变量时,shell 将不知道。当 Expect 脚本完成时,它的变量也消失了。你必须putsexpect_out 缓冲区。

【讨论】:

  • 但是如果我使用单引号,我不能做参数替换。我实际上希望替换 IP 和端口。我将代码更改为粘贴在答案部分的代码,但仍然遇到错误。
  • 您可以在 shell 中 export HOST 和 PORT 变量。在期望中,将它们称为$env(HOST)$env(PORT)
猜你喜欢
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 2016-02-28
相关资源
最近更新 更多