bash 尝试登录到它产生的 ssh 会话时如何预期超时?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7011732/
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:51:45  来源:igfitidea点击:

How to have expect timeout when trying to login to an ssh session it has spawned?

bashsshtimeoutexpect

提问by dunxd

I am writing an bash script that uses expect to login to a bunch of Cisco ASAs (they don't support certificate login, hence using expect), makes a change to the configuration and then logs out.

我正在编写一个 bash 脚本,它使用 expect 登录到一堆 Cisco ASA(它们不支持证书登录,因此使用 expect),对配置进行更改,然后注销。

I'd like the script to move onto the next ASA if it is unable to login.

如果无法登录,我希望脚本移至下一个 ASA。

Here is the script:

这是脚本:

#!/bin/bash
# Scriptname: set-mtu
for asa in $(cat asa-list-temp)
do
        /usr/bin/expect << EndExpect
                spawn ssh admin_15@$asa
                expect "assword:"
                send "pa$$w0rd\r"
                expect ">"
                send "do something\r"
                expect ">"
                send "exit\r"
EndExpect
done

I think I can set a timeout on expect "assword:"but I can't figure out how to get it to close the spawned ssh session and then move onto the next ASA in the for list.

我想我可以设置超时,expect "assword:"但我不知道如何让它关闭生成的 ssh 会话,然后移动到 for 列表中的下一个 ASA。

回答by Sander van Knippenberg

First of all I would use an expect script for this and lose the bash scripting.

首先,我会为此使用一个期望脚本并丢失 bash 脚本。

Then for the expect part: You can do this by using a switch that also matches for timeout (page 12 of exploring expect). In that way you can explicitly have some action when expect timeouts.

然后对于期望部分:您可以通过使用也匹配超时的开关来做到这一点(探索期望的第 12 页)。通过这种方式,您可以在预期超时时明确采取某些行动。

Otherwise by setting the timeout it will just continue with the next command in line.

否则,通过设置超时,它将继续执行下一个命令。

set timeout 60
expect {
 "assword:" {
 }
 timeout {
    exit 1 # to exit the expect part of the script
 }
}

I've created something similar where I used an overall expect script to run an expect script in parallel.

我已经创建了类似的东西,我使用了一个整体的期望脚本来并行运行一个期望脚本。

multiple.exp

多个.exp

#!/bin/sh
# the next line restarts using tclsh \
exec expect "
# The dir from where the commands are executed.
set commandDir "/home/username/scripts/expect/";
set commandName "somecommand.exp";

# The maximum number of simultanious spawned processes.
set maxSpawn 40;

# The maximum timeout in seconds before any of the processes should be finished in minutes
set timeout 20800;
" "$@" # multiple.exp -- # # This file implements the running of multiple expect scripts in parallel. # It has some settings that can be found in multiple.config # # Copyright (c) 2008 # # Author: Sander van Knippenberg ##### # Setting the variables ## source [file dirname $argv0]/.multiple.config # To determine how long the script runs set timingInfo("MultipleProcesses") [clock seconds] # --------------------------------------------------------------------- ###### # Procedure to open a file with a certain filename and retrieve the contents as a string # # Input: filename # Output/Returns: content of the file ## proc openFile {fileName} { if {[file exists $fileName] } { set input [open $fileName r] } else { puts stderr "fileToList cannot open $fileName" exit 1 } set contents [read $input] close $input return $contents } ###### # Procedure to write text to a file with the given filename # # Input: string, filename ## proc toFile {text filename} { # Open the filename for writing set fileId [open $filename "w"] # Send the text to the file. # Failure to add '-nonewline' will reslt in an extra newline at the end of the file. puts -nonewline $fileId $text # Close the file, ensuring the data is written out before continueing with processing close $fileId } # --------------------------------------------------------------------- # Check for the right argument if {$argc > 0 } { set hostfile [lindex $argv 0] } else { puts stderr "$argv0 --- usage: $argv0 <hosts file>" exit 1 } # Create the commands that can be spawned in parallel set commands {} # Open the file with devices set hosts [split [openFile $hostfile] "\n"] foreach host $hosts { if { [string length $host] > 1 } { lappend commands "$commandDir/$commandName $host" # Here you can enter your own command! } } # Run the processes in parallel set idlist {} set runningcount 0 set pattern "This will never match I guess" # Startup the first round of processes until maxSpawn is reached, # or the commands list is empty. while { [llength $idlist] < $maxSpawn && [llength $commands] > 0} { set command [lindex $commands 0] eval spawn $command lappend idlist $spawn_id set commands [lreplace $commands 0 0] incr runningcount set commandInfo($spawn_id) $command set timingInfo($spawn_id) [clock seconds] send_user " $commandInfo($spawn_id) - started\n" } # Finally start running the processes while {$runningcount > 0} { expect { -i $idlist $pattern { } eof { set endedID $expect_out(spawn_id) set donepos [lsearch $idlist $endedID] set idlist [lreplace $idlist $donepos $donepos] incr runningcount -1 set elapsedTime [clock format [expr [clock seconds] - $timingInfo($endedID)] -format "%M:%S (MM:SS)"] send_user " $commandInfo($endedID) - finished in: $elapsedTime\n" # If there are more commands to execute then do it! if {[llength $commands] > 0} { set command [lindex $commands 0] eval spawn $command lappend idlist $spawn_id set commands [lreplace $commands 0 0] incr runningcount set commandInfo($spawn_id) $command set timingInfo($spawn_id) [clock seconds] } } timeout { break } } } set elapsed_time [clock format [expr [clock seconds] - $timingInfo("MultipleProcesses")] -format "%M:%S (MM:SS)"] send_user "$argv0 $argc - finished in: $elapsedTime\n"

multiple.config

多重配置

spawn ssh user@host
expect {
  "assword:" {
    send "password\r"
  }
  timeout {
    exit
  } 
}
expect "prompt>"
. . . 
   login success
. . .

回答by rook

To make the answer clear: the solution is typical, just make timeouttreatment inside the curly braced expectnotation. So, your Tcl/Expectpart in the shell script should be:

为了明确答案:解决方案是典型的,只需timeout在花括号内进行处理即可expect。所以,你在 shell 脚本中的Tcl/Expect部分应该是:

##代码##

Here is another example, how to expect/treat timeoutto resume waiting for the result string while the spawned command is still running.

这是另一个示例,如何timeout在生成的命令仍在运行时期望/处理继续等待结果字符串。