在 Bash 脚本中的单行 Expect 命令中设置和使用变量

在 Bash 脚本中的单行 Expect 命令中设置和使用变量

我有一个数组,$HOSTS其中包含一组主机名。我有一个数据库表,其中包含一组 IP 地址。我想遍历该表中的每个 IP 地址并向hostname -s该地址发送命令 (),然后将输出添加到$HOSTS。远程服务器未配置 PKI,并且脚本必须在无人干预的情况下自动运行。这是一个封闭的网络,root 密码作为变量存储在脚本中 ( $SERVERPASSWORD)。在有人说之前,我意识到将 root 密码放在这样的变量中并不是一个好主意,但在这种情况下,与保护 root 密码相比,不进行任何人为交互更为重要。

这是我当前(已清理)脚本的相关部分:

 for IP in $(sql query that returns a list of IP addresses);do
    HOSTS=($(expect -c 'spawn ssh root@$IP "hostname -s"; expect "assword:";send ""$SERVERPASSWORD"\r";interact' ${HOSTS[@]}))
done

这样做的结果是失败的,说:

无法读取“IP”:执行“spawn ssh root@$IP“hostname -s””时没有这样的变量

我可以用一个来echo $IP代替它,并且它会按预期工作,所以我知道 IP 变量正在循环中填充。

经过一番谷歌搜索,我发现似乎expect需要设置自己的变量,不能使用 Bash 变量,但我发现的所有解决方案都是针对实际的 Expect 脚本,而不是针对在 Bash 脚本中使用 expect。我尝试修改命令,expect set IP $IP -c 'spawn ....'但似乎没有成功。

我该怎么做才能读取这个 For 循环中expect的值?$IP

答案1

摆脱使用全大写变量名的习惯,让它们保留在 shell 中。有一天你会写PATH=something,然后想知道你的脚本为什么坏了

您还可以使用它array+=( "new element" )来附加到数组。

下面,我将单行代码扩展为代码以便于阅读。


这只是 shell 中的一个引用问题。有几种方法可以解决它:

  1. 对期望主体使用双引号。这意味着您必须以不同的方式处理期望引用:您可以对所有双引号使用反斜杠(粗略)或使用括号(这是 Tcl 的单引号机制):

    hosts+=( "$(
        expect -c "
            spawn ssh root@$ip {hostname -s}
            expect {assword:}
            send {$serverPassword}; send \\r
            expect eof
        "
    )" )
    
  2. 将变量传递到环境中。这里我使用带引号的 heredoc,因此您无需担心引用:

    hosts+=( "$(
       ip="$ip" pw="$serverPassword" expect <<<'END_EXPECT'
            spawn ssh root@$env(ip) "hostname -s"
            expect "assword:"
            send "$env(serverPassword)\r"
            expect eof
    END_EXPECT
    )" )
    

相关内容