Tcl expect脚本中的while循环问题

Tcl expect脚本中的while循环问题,tcl,Tcl,我编写了一个expect脚本,其工作原理如下: ssh到服务器1 从server1 ssh到另一台服务器server2 从server2到server3,然后sudo进入用户并运行命令 在脚本中,我从名为hostnames.out和commands.out的两个文件中读取要执行的主机名和命令。我使用while循环遍历hostnames.out中的每个条目,并从commands.out文件中运行命令 我在hostnames.out中使用一个条目测试了我的脚本,它可以正常工作,但是当我添加多行时,它

我编写了一个expect脚本,其工作原理如下:

  • ssh到服务器1
  • 从server1 ssh到另一台服务器server2
  • 从server2到server3,然后sudo进入用户并运行命令
  • 在脚本中,我从名为hostnames.out和commands.out的两个文件中读取要执行的主机名和命令。我使用while循环遍历hostnames.out中的每个条目,并从commands.out文件中运行命令

    我在hostnames.out中使用一个条目测试了我的脚本,它可以正常工作,但是当我添加多行时,它不会从第二行开始在hostnames上运行命令

    commands.out文件的格式为(每行一个命令):



    据我所知,主要问题是不同主机上的子进程链很复杂,没有得到正确清理。不一致的缩进使代码更难阅读,这使问题更加复杂

    关键是,您希望server1和server2上的ssh会话只通过ssh连接到链中的下一个服务器,server3上的ssh会话只执行sudo。最简单的修复方法是使用
    exec-ssh
    而不是
    ssh
    exec-sudo
    而不是
    sudo
    。然后,在最内层执行
    exit
    将导致所有这些中间程序也终止,并且将触发
    expect eof

    spawn -noecho ssh $ssh1_usr@$ssh1
    expect {
        "*route*" { puts "login failed"; exit 1 }
        "timed out" { puts "login failed timed out"; exit 1 }
        "*password:" { send "$ssh1_pwd\r"; exp_continue }
         -re $prompt { send "whoami\r" }
    }
    expect -re $prompt  { 
        send "exec ssh $ods_usr@$ods\r"
    }
    expect {
        "password:" { send "$ods_pwd\r"; exp_continue }
        -re $prompt { send "whoami\r" }
    }
    expect -re $prompt  {
        send "exec ssh $serv1_usr@$serv1\r"
    }
    expect {
        "password:" { send "$serv1_pwd\r"; exp_continue }
        -re $prompt { send "whoami\r" }
    }
    
    # You seem to be missing the sudo here?
    
    foreach a [split $file_data "\n"] {
        expect -re $prompt
        send "$a"
    }
    
    expect -re $prompt
    send "exit\r"
    expect eof
    close;          ### TERMINATE THE SPAWN. IMPORTANT!
    
    您还遇到了一个问题,即您在使用
    [list$file\u data]
    时,本应使用
    [split$file\u data”\n]
    将其按行拆分


    对于每一组凭证,都需要循环上面的代码。这一部分最容易写成这样的内容(考虑到您确实没有足够的数据行需要流处理):



    我单独建议在所有中间服务器上设置SSH公钥,并使用
    -A
    选项进行SSH。这可以在不影响安全性的情况下大大简化身份验证/授权部分。

    您是否收到任何错误消息?不,我在hostnames.out文件中添加第二行时没有收到任何错误消息。另外请注意,您可以将要执行的命令传递给ssh,如
    sshuser1@serv1sshuser2@serv2sudo yourcommand
    。现在你只需要处理密码的事情。 server1 user password server2 user password server3 user password
    #!/usr/bin/expect
    #####################################################
    # script to automate manual works - remote 2        #
    # Gopinath                                          #
    #####################################################
    #Variable declaration:
    
    #Setting variable "prompt" for multiple prompts:
    set prompt {[]$#%]\s*$}
    
    #Reading commands list from file:
    
    set fp1 [open "commands_list_2.out" "r"]
    set file_data [read $fp1]
    close $fp1
    
    
    #  read the hosts file one line at a time
    #  There should be no new line at the end of the hostnames.out file
    
         set fp [open "hostnames_2.out" "r"]
    
         while { [gets $fp data] >= 0 } {
    
              set ssh1 [lindex $data 0]
              set ssh1_usr [lindex $data 1]
              set ssh1_pwd [lindex $data 2]
          set ods [lindex $data 3]
          set ods_usr [lindex $data 4]
              set ods_pwd [lindex $data 5]
          set serv1 [lindex $data 6]
          set serv1_usr [lindex $data 7]
          set serv1_pwd  [lindex $data 8]
    
              puts $ssh1 
          puts $ssh1_usr
              puts $ssh1_pwd
          puts $ods
          puts $ods_usr
          puts $ods_pwd
          puts $serv1
          puts $serv1_usr
              puts $serv1_pwd
    
         spawn -noecho ssh $ssh1_usr@$ssh1
         expect { 
    
            "*password:" { send "$ssh1_pwd\r"}
            "*route*" { puts "login failed"; exit 1 }
            "timed out" { puts "login failed timed out"; exit 1 }
             }
    
          expect {
                   -re $prompt { send "whoami\r"}
                 }            
    
    
                      expect -re $prompt  { 
    
                                send  "ssh $ods_usr@$ods\r" }           
                      expect {
                         "password:" { send "$ods_pwd\r" }
                             }
                     }
    
    
               expect {
             -re $prompt { send "whoami\r"}
              }
    
    
                       expect -re $prompt  {
    
                                send  "ssh $serv1_usr@$serv1\r" }
                      expect {
                         "password:" { send "$serv1_pwd\r" }
                             }
    
                       expect -re $prompt 
    
    
             foreach a [list $file_data] {
             send "$a"
             expect -re prompt
             }
              expect -re prompt {   
                  send "exit\r"
                  }
         expect eof
         close $fp
    `
    
    spawn -noecho ssh $ssh1_usr@$ssh1
    expect {
        "*route*" { puts "login failed"; exit 1 }
        "timed out" { puts "login failed timed out"; exit 1 }
        "*password:" { send "$ssh1_pwd\r"; exp_continue }
         -re $prompt { send "whoami\r" }
    }
    expect -re $prompt  { 
        send "exec ssh $ods_usr@$ods\r"
    }
    expect {
        "password:" { send "$ods_pwd\r"; exp_continue }
        -re $prompt { send "whoami\r" }
    }
    expect -re $prompt  {
        send "exec ssh $serv1_usr@$serv1\r"
    }
    expect {
        "password:" { send "$serv1_pwd\r"; exp_continue }
        -re $prompt { send "whoami\r" }
    }
    
    # You seem to be missing the sudo here?
    
    foreach a [split $file_data "\n"] {
        expect -re $prompt
        send "$a"
    }
    
    expect -re $prompt
    send "exit\r"
    expect eof
    close;          ### TERMINATE THE SPAWN. IMPORTANT!
    
    set fp [open "hostnames_2.out" "r"]
    set hostnamedata [split [read $fp] "\n"]
    close $fp
    
    foreach line $hostnamedata {
        lassign $line  ssh1 ssh1_usr ssh1_pwd  ods ods_usr ods_pwd  serv1 serv1_usr serv1_pwd
    
        # The code from above goes here
    }