简体   繁体   English

在bash数组中将变量传递给`expect`

[英]Passing variable to `expect` in bash array

I am trying to use a FOR loop to iterate over IP addresses (in a bash array), logs in, runs a script and then exits. 我正在尝试使用FOR循环遍历IP地址(在bash数组中),登录,运行脚本然后退出。 The array is called ${INSTANCE_IPS[@]}. 该数组称为$ {INSTANCE_IPS [@]}。 The following code doesn't work though, as expect doesn't seem to be able to accept the variable $instance. 但是,以下代码无法正常工作,因为expect似乎无法接受$ instance变量。

for instance in ${INSTANCE_IPS[@]}
  do
  echo $instance
  /usr/bin/expect -c '
  spawn ssh root@$instance;
  expect "?assword: ";
  send "<password>\r";
  expect "# ";
  send ". /usr/local/bin/bootstrap.sh\r";
  expect "# ";
  send "exit\r" '
done

However, expect complains with: 但是, expect抱怨:

can't read "instance": no such variable
    while executing
"spawn ssh root@$instance"

There is another question on stackoverflow located here , that uses environmental variables to achieve this, however it doesn't allow me to iterate through different IP addresses like I can in an array. 有在位于计算器另一个问题在这里 ,使用环境变量来实现这一点,但是它不允许像我可以在一个阵列我通过不同的IP地址进行迭代。

Any help is appreciated. 任何帮助表示赞赏。

Cheers 干杯

The problem is with quoting. 问题在于报价。 Single quotes surrounding the whole block don't let Bash expand variables ( $instance ). 围绕整个块的单引号不允许Bash扩展变量( $instance )。

You need to switch to double quotes. 您需要切换到双引号。 But then, double quotes inside double quotes are not allowed (unless you escape them), so we are better off using single quotes with expect strings. 但是然后,不允许在双引号内使用双引号(除非您将其转义),因此最好使用带有expect字符串的单引号。

Try instead: 请尝试:

for instance in ${INSTANCE_IPS[@]}
  do
  echo $instance
  /usr/bin/expect -c "
  spawn ssh root@$instance;
  expect '?assword: ';
  send '<password>\r';
  expect '# ';
  send '. /usr/local/bin/bootstrap.sh\r';
  expect '# ';
  send 'exit\r' "
done
for instance in ${INSTANCE_IPS[&]} ;  do
    echo $instance
    /usr/bin/expect -c '
    spawn ssh root@'$instance' "/usr/local/bin/bootstrap.sh"
    expect "password:"
    send "<password>\r"
    expect eof'
done

From the ssh man page: 在ssh手册页中:

If command is specified, it is executed on the remote host instead of a login shell.

Specifying a command means expect doesn't have to wait for # to execute your program, then wait for another # just to send the command exit . 指定命令意味着期望不必等待#执行程序,然后等待另一个#仅发送命令exit Instead, when you specify a command to ssh, it executes that command; 相反,当您指定要使用ssh的命令时,它将执行该命令。 it exits when done; 完成后退出; and then ssh automatically closes the connection. 然后ssh自动关闭连接。

Alternately, put the value in the environment and expect can find it there 或者,将值放在环境中,并期望在那里找到它

for instance in ${INSTANCE_IPS[&]} ;  do
    echo $instance
    the_host=$instance /usr/bin/expect -c '
        spawn ssh root@$env(the_host) ...

Old thread, and one of many, but I've been working on expect for several days. 旧线程,也是其中的一个,但我已经在expect工作了几天。 For anyone who comes across this, I belive I've found a doable solution to the problem of passing bash variables inside an expect -c script: 对于遇到此问题的任何人,我相信我已经找到了一个可行的解决方案,可以解决在expect -c脚本中传递bash变量的问题:

#!/usr/bin/env bash
password="TopSecret"

read -d '' exp << EOF
set user "John Doe"
puts "\$user"
puts "$password"
EOF

expect -c "$exp"

Please note that escaping quotations are typically a cited issue (as @Roberto Reale stated above), which I've solved using a heredoc EOF method, before passing the bash-variable-evaluated string to expect -c . 请注意,转义引号通常是一个引用的问题(如上面的@Roberto Reale所述), 将bash-variable-evaluated字符串传递给expect -c 之前 ,我已经使用heredoc EOF方法解决了该问题。 In contrast to escaping quotes, all native expect variables will need to be escaped with \\$ (I'm not here to solve all first-world problems--my afternoon schedule is slightly crammed), but this should greatly simplify the problem with little effort. 与转义引号相反, 所有本机的expect变量都需要使用\\$进行转义 (我不是在这里解决所有第一手问题,我的下午时间安排很挤),但这应该可以大大简化问题努力。 Let me know if you find any issues with this proof of concept. 如果您对此概念证明有任何疑问,请告诉我。

tl;tr: Been creating an [ expect ] daemon script with user authentication and just figured this out after I spent a whole day creating separated bash/expect scripts, encrypting my prompted password (via bash) with a different /dev/random salt each iteration, saving the encrypted password to a temp file and passing the salt to the expect script (highly discouraging anyone from easily discovering the password via ps , but not preventative since the expect script could be replaced). tl; tr:一直在使用用户身份验证创建[ expect ]守护程序脚本,并且我花了一整天时间创建单独的bash / expect脚本,并分别使用不同的/dev/random salt加密提示的密码(通过bash) ,才弄清楚了这一点迭代,将加密的密码保存到临时文件中,然后将salt传递给Expect脚本(强烈劝阻任何人不要通过ps轻易地找到密码,但不能阻止,因为可以替换期望脚本)。 Now I should be able to effectively keep it in memory instead. 现在,我应该能够有效地将其保留在内存中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM