如何使用 Expect/Tcl 中的数组进行 ssh?
How to ssh with Arrays in Expect/Tcl?
我可以成功地生成一个 ssh 会话执行一些 scp 并在 Excpet/Tcl 中执行一个 bash 脚本。但是,当我尝试通过 for 循环和数组 ssh 进入多个系统时,出现 ssh: Could not resolve hostname $SOME_HOST: Temporary failure in name resolution
错误。
我真的很希望能够通过使用数组来实现这一点,但是无论出于何种原因,Expect/Tcl 在尝试将数组与 ssh 一起使用时遇到问题。
#arrays
array set userArray {
0 $A_USERNAME
1 $A_USERNAME
2 $A_USERNAME
3 $B_USERNAME
4 $B_USERNAME
5 $A_USERNAME
6 $A_USERNAME
7 $A_USERNAME
8 $A_USERNAME
9 $A_USERNAME
10 $B_USERNAME
#11 $B_USERNAME
}
array set hostArray {
0 $A_HOST
1 $B_HOST
2 $C_HOST
3 $D_HOST
4 $E_HOST
5 $F_HOST
6 $H_HOST
7 $I_HOST
8 $J_HOST
9 $K_HOST
10 $L_HOST
#11 $M_HOST
}
array set sshPasswordArray {
0 "placeholder0"
1 "placeholder1"
2 "placeholder2"
3 "placeholder3"
4 "placeholder4"
5 "placeholder5"
6 "placeholder6"
7 "placeholder7"
8 "placeholder8"
9 "placeholder9"
10 "placeholder10"
#11 "placeholder11"
}
#expect "$ " { send -- "cd /tmp/\r" }
#This loop will step through every system on a system sshing and then running $LINUX_HARDWARE_COLLECTION_FILE on said system.
for { set index 0 } { $index < $NUM_SYSTEMS_IN_A_SYSTEM } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l $userArray($index) $hostArray($index)
expect "*?assword:"
send "$sshPasswordArray($index)\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
有谁知道如何才能成功做到这一点?问题似乎是 Excpet/Tcl 不想读取我的数组的值。对于上面的代码,假设 A_USERNAME
、B_USERNAME
、各种主机和密码都是有效的字符串。
array set
命令,当这样使用时,不会替换那些定义中的变量。例如,hostArray(0)
设置为文字字符 $A_HOST
。解决此问题的简单方法是使用 subst
命令在使用前 post 处理值。
for { set index 0 } { $index < $NUM_SYSTEMS_IN_A_SYSTEM } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l \
[subst $userArray($index)] [subst $hostArray($index)]
expect "*?assword:"
send "$sshPasswordArray($index)"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
另外记得在密码的send
后面加个\r
(模拟按Return 键)并且不要忘记 close
在循环结束时生成的子进程。 (这对于 10 个项目通常并不重要,但是您可以同时打开的虚拟终端数量相当少,并且包括您机器上的所有其他用户;最好保持同时打开的数量尽可能小尽可能。)
您也可以在 array set
处使用它,但是如果您的变量中有空格,它可能会松动,所以我真的不推荐它:
array set userArray [subst {
0 $A_USERNAME
1 $A_USERNAME
... ...
}]
注意:array set
根本不支持评论格式。您在示例中使用键 #11
进行了输入…
Tcl 中的数组是将任意字符串映射到字符串的关联数组。
Tcl 中的列表是数字索引数组。
你也可以这样做:
set hostArray [list $A_HOST $B_HOST $C_HOST $D_HOST $E_HOST $F_HOST $H_HOST $I_HOST $J_HOST $K_HOST $L_HOST $M_HOST]
set userArray [list $A_USERNAME $A_USERNAME $A_USERNAME $B_USERNAME $B_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $B_USERNAME $B_USERNAME]
set sshPasswordArray {
"placeholder0"
"placeholder1"
"placeholder2"
"placeholder3"
"placeholder4"
"placeholder5"
"placeholder6"
"placeholder7"
"placeholder8"
"placeholder9"
"placeholder10"
"placeholder11"
}
然后,迭代
for { set index 0 } { $index < [llength $userArray] } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l [lindex $userArray $index] [lindex $hostArray $index]
expect "*?assword:"
send "[lindex $sshPasswordArray $index]\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
或者,使用 foreach 更具可读性
foreach user $userArray host $hostArray sshPassword $sshPasswordArray {
spawn ssh -o StrictHostKeyChecking=no -l $user $host
expect "*?assword:"
send "$sshPassword\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
我可以成功地生成一个 ssh 会话执行一些 scp 并在 Excpet/Tcl 中执行一个 bash 脚本。但是,当我尝试通过 for 循环和数组 ssh 进入多个系统时,出现 ssh: Could not resolve hostname $SOME_HOST: Temporary failure in name resolution
错误。
我真的很希望能够通过使用数组来实现这一点,但是无论出于何种原因,Expect/Tcl 在尝试将数组与 ssh 一起使用时遇到问题。
#arrays
array set userArray {
0 $A_USERNAME
1 $A_USERNAME
2 $A_USERNAME
3 $B_USERNAME
4 $B_USERNAME
5 $A_USERNAME
6 $A_USERNAME
7 $A_USERNAME
8 $A_USERNAME
9 $A_USERNAME
10 $B_USERNAME
#11 $B_USERNAME
}
array set hostArray {
0 $A_HOST
1 $B_HOST
2 $C_HOST
3 $D_HOST
4 $E_HOST
5 $F_HOST
6 $H_HOST
7 $I_HOST
8 $J_HOST
9 $K_HOST
10 $L_HOST
#11 $M_HOST
}
array set sshPasswordArray {
0 "placeholder0"
1 "placeholder1"
2 "placeholder2"
3 "placeholder3"
4 "placeholder4"
5 "placeholder5"
6 "placeholder6"
7 "placeholder7"
8 "placeholder8"
9 "placeholder9"
10 "placeholder10"
#11 "placeholder11"
}
#expect "$ " { send -- "cd /tmp/\r" }
#This loop will step through every system on a system sshing and then running $LINUX_HARDWARE_COLLECTION_FILE on said system.
for { set index 0 } { $index < $NUM_SYSTEMS_IN_A_SYSTEM } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l $userArray($index) $hostArray($index)
expect "*?assword:"
send "$sshPasswordArray($index)\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
有谁知道如何才能成功做到这一点?问题似乎是 Excpet/Tcl 不想读取我的数组的值。对于上面的代码,假设 A_USERNAME
、B_USERNAME
、各种主机和密码都是有效的字符串。
array set
命令,当这样使用时,不会替换那些定义中的变量。例如,hostArray(0)
设置为文字字符 $A_HOST
。解决此问题的简单方法是使用 subst
命令在使用前 post 处理值。
for { set index 0 } { $index < $NUM_SYSTEMS_IN_A_SYSTEM } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l \
[subst $userArray($index)] [subst $hostArray($index)]
expect "*?assword:"
send "$sshPasswordArray($index)"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
另外记得在密码的send
后面加个\r
(模拟按Return 键)并且不要忘记 close
在循环结束时生成的子进程。 (这对于 10 个项目通常并不重要,但是您可以同时打开的虚拟终端数量相当少,并且包括您机器上的所有其他用户;最好保持同时打开的数量尽可能小尽可能。)
您也可以在 array set
处使用它,但是如果您的变量中有空格,它可能会松动,所以我真的不推荐它:
array set userArray [subst {
0 $A_USERNAME
1 $A_USERNAME
... ...
}]
注意:array set
根本不支持评论格式。您在示例中使用键 #11
进行了输入…
Tcl 中的数组是将任意字符串映射到字符串的关联数组。
Tcl 中的列表是数字索引数组。
你也可以这样做:
set hostArray [list $A_HOST $B_HOST $C_HOST $D_HOST $E_HOST $F_HOST $H_HOST $I_HOST $J_HOST $K_HOST $L_HOST $M_HOST]
set userArray [list $A_USERNAME $A_USERNAME $A_USERNAME $B_USERNAME $B_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $A_USERNAME $B_USERNAME $B_USERNAME]
set sshPasswordArray {
"placeholder0"
"placeholder1"
"placeholder2"
"placeholder3"
"placeholder4"
"placeholder5"
"placeholder6"
"placeholder7"
"placeholder8"
"placeholder9"
"placeholder10"
"placeholder11"
}
然后,迭代
for { set index 0 } { $index < [llength $userArray] } { incr index } {
puts "In loop: $index"
spawn ssh -o StrictHostKeyChecking=no -l [lindex $userArray $index] [lindex $hostArray $index]
expect "*?assword:"
send "[lindex $sshPasswordArray $index]\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}
或者,使用 foreach 更具可读性
foreach user $userArray host $hostArray sshPassword $sshPasswordArray {
spawn ssh -o StrictHostKeyChecking=no -l $user $host
expect "*?assword:"
send "$sshPassword\r"
#do some stuff here including executing $LINUX_HARDWARE_COLLECTION_FILE...
}