while循环问题在expect脚本中

时间:2016-01-23 09:08:48

标签: tcl

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

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

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

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

    ls -lrt
    hostname
    whoami
    

    hostnames.out文件的格式为:

    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
    `
    

1 个答案:

答案 0 :(得分:1)

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

关键是你希望你的server1和server2上的ssh会话只是 ssh到链中的下一个服务器,而server3上的ssh会话只需 做一个sudo。最简单的解决方法是使用exec ssh代替sshexec 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_data]进行分解,那么您还遇到了使用[split $file_data "\n"]的问题。

上面的代码需要针对每组凭据进行循环。这部分最容易写成这样的东西(鉴于你真的没有足够的数据行需要流处理):

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
}

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