在 bash 脚本中期望:expect_out 不打印出缓冲区

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5589577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:23:39  来源:igfitidea点击:

Expect in bash script: expect_out not printing out buffer

bashexpect

提问by Pkp

I am trying to capture the output of "dir" command by logging into a switch, but i am unable to do so. I am using expect within bash. I am making use of expect_out to capture output of that command in a buffer and print it out. Actually I want to capture the output and perform some operations on it.
SCript:

我试图通过登录交换机来捕获“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"  

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>  

After these prompts are displayed, the scripts just exits. Kindly help.

显示这些提示后,脚本就退出了。请帮忙。

EDIT:

编辑:

I split it now so that I can use parameter substitution as well as single quotes. Now I am facing different error.

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

Script:

脚本:

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"
}
'

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"
}
"

EDIT 2: Hello Chris/all,

编辑 2:你好,克里斯/大家,

I changed it to according to your suggestions. But am still facing erros.

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

Script:

脚本:

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 "======="  

Output:

输出:

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>

=======

Hence to circumvent the error, I changed, the line

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

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

to

puts '"$expect_out(buffer)"'

But then I am getting no error, but the output of dir is also not getting printed. Something like:

但是后来我没有收到任何错误,但是 dir 的输出也没有打印出来。就像是:

Prompt>

Prompt> (buffer)

回答by Chris Johnsen

The second of your “split” Expect programs does not have access to the spawned telnetprocess. When you split them like that, you made them independent (one can not access the variables or state of the other; actually by the time the second one has started the first one, and its telnetprocess, no longer exist).

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



The shell will automatically concatenate any strings (that are not separated by unquoted/unescaped whitespace) without regard to the kind of quotes (if any) they use. This means you can start put the first part of your Expect program in single quotes, switch to double quotes for the parameter substitution, and then go back to single quotes for the rest of the program (to avoid having to escape any of "$\`that occur in your Expect code).

shell 会自动连接任何字符串(没有被未加引号/未转义的空格分隔),而不考虑它们使用的引号类型(如果有的话)。这意味着你可以开始放单引号,开关为参数替换双引号的期待计划的第一部分,然后回去单引号的程序的其余部分(以避免逃避任何"$\`发生在您的预期代码)。

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

It uses single quotes to protect most of the program, but switches back to double quotes to let the shell substitute the its HOST and IP parameters into the text of the Expect program.

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



Next, the shell that started expectcan not access variable set inside the Expect program. The normal way to collect output from a child process is to have it write to stdout or stderr and have the shell collect the output via a command substitution ($()).

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

In Tcl (and Expect), you can use putsto send a string to stdout. But, by default, Expect will also send to stdout the normal “interaction” output (what it receives from any spawned commands and what it sent to them; i.e. what you would see if you were running the spawned command manually). You can disable this default logging with log_user 0.

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

You might write your program like this:

你可以这样写你的程序:

#!/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 "======="

回答by glenn Hymanman

Because your expect script is enclosed in double quotes, the shell is expanding $expect_outto an empty string. Put the body of the expect script in single quotes.

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

When you set a variable in expect, the shell will have no idea. When the expect script completes, it's variables vanish too. You have to putsthe expect_out buffer.

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