Expect 脚本没有退出我设置的代码
Expect script is not exiting with code I set it to
我尝试在 codereview 社区中发布这个,但是没有期望标签,而且我没有足够的业力来创建标签。
我编写了一个 expect 脚本来登录服务器或 运行 一个简单的(通常是单个)命令和 return 输出。
我有两个问题和一个愿望
- 命令 return 什么都没有——即
ssh2server user host false
——超时并出现错误(因为我没有捕获超时,虽然我想我应该)而不是 return什么都没有。
- 我可以捕获程序的 return 代码,但我无法使用适当的代码将其退出。
- 有没有一种方法可以获取被调用程序的输出并return以相同的方式(远程标准输出到本地标准输出,远程标准错误到本地标准错误)?
此外,任何评论或(建设性的)批评将不胜感激。
#!/usr/bin/expect -f
if {[info exists ::env(SSH2SERVER_PASSWORD)]} {
set password "$env(SSH2SERVER_PASSWORD)"
} else {
puts "SSH2SERVER_PASSWORD not set"
exit 1
}
if {[llength $argv] < 2} {
puts "usage: ssh2server user server"
exit 1
}
set user [lindex $argv 0]
set server [lindex $argv 1]
set command [lrange $argv 2 end]
set pwd_prompt "*assword:"
set prompt "$ "
set rc 0
expect_before {
#timeout { send_user 'timeout' ; exit 2 }
timeout { send_user 'timeout' ; set rc 2}
}
log_user 0
spawn ssh $user@$server
expect "$pwd_prompt" { send -- "$password\r" }
if { $command == "" } {
interact
} else {
expect {
"$prompt" {
send -- "PROMPT_COMMAND=\rPS1='_MYPROMPT_'\r$command\r"
#expect -re "$command\r\n(.*)\r\n\[^\r]*\[#$%]"
expect -re "$command\r\n(.*)\r\n\[^\r]*_MYPROMPT_"
set results $expect_out(1,string)
puts $results
send -- "^D"
expect eof
#catch wait ec
#set rc [lindex $ec 3]
#puts [lindex $ec 3]
#exit [lindex $ec 3]
}
#eof { send_user $expect_out(buffer); exit 3}
eof { send_user $expect_out(buffer); set rc 3}
}
}
log_user 1
lassign [wait] pid spawnid os_flag rc
#puts $rc # outputs correct value
exit $rc
我怀疑是这个问题:
send -- "^D"
您发送的不是 Ctrl-D,而是字符 ^ 和 D.
发送 Ctrl-D
send -- ""
要解决 "no output, timeout" 问题,您需要更改预期的正则表达式:对于这种情况,换行符太多。使用 expect -d
会向您揭示这一点。像这样:
send -- "unset PROMPT_COMMAND; PS1='_MYPROMPT_'\r"
expect -re "_MYPROMPT_$"
send -- "$command\r"
expect -re "$command(.*)\r\n_MYPROMPT_$"
捕获括号的内容现在可能为空。
为了清楚起见,我把设置提示分开了。
要捕获命令的退出状态,您可能需要这样做:
send -- "$command; echo $?\r"
expect -re "$command(.*)\r\n(\d+)\r\n_MYPROMPT_$"
set results [regsub {^\r\n} $expect_out(1,string) ""]
set status $expect_out(2,string)
我不认为您可以使用expect
命令将stdout 和stderr 分开。我认为这两个流都被捕获为 "output"。 (我附近没有我的 Exploring Expect 书来确认)
如果这很重要,您可能需要调用命令将 stdout and/or stderr 重定向到文件,然后 cat
并捕获文件内容。
我尝试在 codereview 社区中发布这个,但是没有期望标签,而且我没有足够的业力来创建标签。
我编写了一个 expect 脚本来登录服务器或 运行 一个简单的(通常是单个)命令和 return 输出。
我有两个问题和一个愿望
- 命令 return 什么都没有——即
ssh2server user host false
——超时并出现错误(因为我没有捕获超时,虽然我想我应该)而不是 return什么都没有。 - 我可以捕获程序的 return 代码,但我无法使用适当的代码将其退出。
- 有没有一种方法可以获取被调用程序的输出并return以相同的方式(远程标准输出到本地标准输出,远程标准错误到本地标准错误)?
此外,任何评论或(建设性的)批评将不胜感激。
#!/usr/bin/expect -f
if {[info exists ::env(SSH2SERVER_PASSWORD)]} {
set password "$env(SSH2SERVER_PASSWORD)"
} else {
puts "SSH2SERVER_PASSWORD not set"
exit 1
}
if {[llength $argv] < 2} {
puts "usage: ssh2server user server"
exit 1
}
set user [lindex $argv 0]
set server [lindex $argv 1]
set command [lrange $argv 2 end]
set pwd_prompt "*assword:"
set prompt "$ "
set rc 0
expect_before {
#timeout { send_user 'timeout' ; exit 2 }
timeout { send_user 'timeout' ; set rc 2}
}
log_user 0
spawn ssh $user@$server
expect "$pwd_prompt" { send -- "$password\r" }
if { $command == "" } {
interact
} else {
expect {
"$prompt" {
send -- "PROMPT_COMMAND=\rPS1='_MYPROMPT_'\r$command\r"
#expect -re "$command\r\n(.*)\r\n\[^\r]*\[#$%]"
expect -re "$command\r\n(.*)\r\n\[^\r]*_MYPROMPT_"
set results $expect_out(1,string)
puts $results
send -- "^D"
expect eof
#catch wait ec
#set rc [lindex $ec 3]
#puts [lindex $ec 3]
#exit [lindex $ec 3]
}
#eof { send_user $expect_out(buffer); exit 3}
eof { send_user $expect_out(buffer); set rc 3}
}
}
log_user 1
lassign [wait] pid spawnid os_flag rc
#puts $rc # outputs correct value
exit $rc
我怀疑是这个问题:
send -- "^D"
您发送的不是 Ctrl-D,而是字符 ^ 和 D.
发送 Ctrl-D
send -- ""
要解决 "no output, timeout" 问题,您需要更改预期的正则表达式:对于这种情况,换行符太多。使用 expect -d
会向您揭示这一点。像这样:
send -- "unset PROMPT_COMMAND; PS1='_MYPROMPT_'\r"
expect -re "_MYPROMPT_$"
send -- "$command\r"
expect -re "$command(.*)\r\n_MYPROMPT_$"
捕获括号的内容现在可能为空。
为了清楚起见,我把设置提示分开了。
要捕获命令的退出状态,您可能需要这样做:
send -- "$command; echo $?\r"
expect -re "$command(.*)\r\n(\d+)\r\n_MYPROMPT_$"
set results [regsub {^\r\n} $expect_out(1,string) ""]
set status $expect_out(2,string)
我不认为您可以使用expect
命令将stdout 和stderr 分开。我认为这两个流都被捕获为 "output"。 (我附近没有我的 Exploring Expect 书来确认)
如果这很重要,您可能需要调用命令将 stdout and/or stderr 重定向到文件,然后 cat
并捕获文件内容。