Bash脚本中的期望:Expect_out不会打印出缓冲区

问题描述 投票:4回答:2

我正在尝试通过登录到交换机来捕获“ 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]]"'

to

puts '"$expect_out(buffer)"'

但是然后我没有收到任何错误,但是dir的输出也没有得到打印。类似于:

Prompt>

Prompt> (buffer)
bash expect
2个回答
3
投票

您的“分割”的Expect程序的第二个程序无权访问产生的telnet进程。像这样拆分它们时,就使它们独立(一个不能访问另一个的变量或状态;实际上,第二个启动第一个时,它的telnet进程不再存在) 。


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

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

[它使用单引号保护大多数程序,但是切换回双引号,以使外壳程序将其HOST和IP参数替换为Expect程序的文本。


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

在Tcl(和Expect)中,您可以使用puts将字符串发送到stdout。但是,默认情况下,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 "======="

0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.