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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23233922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:17:08  来源:igfitidea点击:

Passing variable to `expect` in bash array

linuxbashvariablesfor-loopexpect

提问by user3558925

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. The array is called ${INSTANCE_IPS[@]}. The following code doesn't work though, as expectdoesn't seem to be able to accept the variable $instance.

我正在尝试使用 FOR 循环遍历 IP 地址(在 bash 数组中)、登录、运行脚本然后退出。该数组称为 ${INSTANCE_IPS[@]}。但是,以下代码不起作用,因为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, expectcomplains 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.

位于此处的stackoverflow 上还有另一个问题,它使用环境变量来实现这一点,但是它不允许我像在数组中那样遍历不同的 IP 地址。

Any help is appreciated.

任何帮助表示赞赏。

Cheers

干杯

回答by Roberto Reale

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 expectstrings.

您需要切换到双引号。但是,双引号内的双引号是不允许的(除非你对它们进行转义),所以我们最好对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

回答by Keith Reynolds

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.

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. Instead, when you specify a command to ssh, it executes that command; it exits when done; and then ssh automatically closes the connection.

指定一个命令意味着 expect 不必等待#执行你的程序,然后等待另一个#只是发送命令exit。相反,当您向 ssh 指定命令时,它会执行该命令;完成后退出;然后 ssh 自动关闭连接。

回答by glenn Hymanman

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) ...

回答by Jonathan

Old thread, and one of many, but I've been working on expectfor several days. For anyone who comes across this, I belive I've found a doable solution to the problem of passing bashvariables inside an expect -cscript:

旧线程,其中之一,但我已经工作expect了好几天。对于遇到此问题的任何人,我相信我已经找到了解决bashexpect -c脚本中传递变量问题的可行解决方案:

#!/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 heredocEOFmethod, beforepassing the bash-variable-evaluated string to expect -c. In contrast to escaping quotes, all native expectvariables will need to be escaped with \$(I'm not here to solve allfirst-world problems--my afternoon schedule is slightly crammed), but this should greatly simplify the problem with little effort. Let me know if you find any issues with this proof of concept.

请注意,转义引号通常是一个引用问题(如上面@Roberto Reale 所述)heredocEOF将 bash 变量评估字符串传递给expect -c. 与转义引号相反,所有本机expect变量都需要转义\$(我不是在这里解决所有第一世界问题——我下午的日程安排有点拥挤),但这应该可以毫不费力地大大简化问题。如果您发现此概念证明有任何问题,请告诉我。

tl;tr: Been creating an [expect] daemon script with user authentication and just figured this out afterI spent a whole day creating separated bash/expect scripts, encrypting my prompted password (via bash) with a different /dev/randomsalt 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). Now I should be able to effectively keep it in memory instead.

tl;tr:一直在创建一个expect具有用户身份验证的 [ ] 守护进程脚本,并且我花了一整天创建单独的 bash/expect 脚本后才发现这一点,/dev/random每次迭代都用不同的盐加密我的提示密码(通过 bash),保存加密的密码到临时文件并将盐传递给期望脚本(强烈劝阻任何人通过 轻松发现密码ps,但不是预防性的,因为可以替换期望脚本)。现在我应该能够有效地将它保存在内存中。