在 bash 脚本中嵌入期望
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41165719/
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
Embedding an expect inside a bash script
提问by Marses
I realise similar questions have been asked before, I looked at them and tried to apply what I learned and have the following script:
我意识到以前也有人问过类似的问题,我查看了它们并尝试应用我所学到的知识并编写以下脚本:
#!/bin/bash
if [ `hostname` = 'EXAMPLE' ]
then
/usr/bin/expect << EOD
spawn scp -rp host:~/outfiles/ /home/USERNAME/outfiles/
expect "id_rsa':"
send "PASSWORD\r"
interact
spawn scp -rp host:~/errfiles/ /home/USERNAME/errfiles/
expect "id_rsa':"
send "PASSWORD\r"
interact
expect eof
EOD
echo 'Successful download'
fi
Unfortunately it doesn't seem to work and I get an error message:
不幸的是,它似乎不起作用,我收到一条错误消息:
spawn scp -rp host:~/outfiles/ /home/USERNAME/outfiles/
Enter passphrase for key '/home/USERNAME/.ssh/id_rsa': interact: spawn id exp0 not open
while executing
"interact"
I don't know what it means and why it doesn't work. However, when I wrote the above code using a not-embedded expect script:
我不知道这意味着什么以及为什么它不起作用。但是,当我使用未嵌入的 expect 脚本编写上述代码时:
#!/usr/bin/expect
spawn scp -rp host:~/outfiles/ /home/USERNAME/outfiles/
expect "id_rsa':"
send "PASSWORD\r"
interact
spawn scp -rp host:~/errfiles/ /home/USERNAME/errfiles/
expect "id_rsa':"
send "PASSWORD\r"
interact
It worked without any problems. So what am I doing wrong?
它没有任何问题。那我做错了什么?
NOTE: Often when someone posts a question about using expect
to use scp
or ssh
the answer given is to use rsa keys. I tried, unfortunately on one of my computers there is some crappy bug with the gnome keyring that means that I can't remove my password from the rsa-key, which is exactly why I'm trying to write the above script with an if statement. So please don't tell me to use rsa keys.
注:通常当有人发布一个有关使用问题,expect
使用scp
或ssh
给出的答案是使用RSA密钥。我试过了,不幸的是,在我的一台计算机上,gnome 密钥环存在一些糟糕的错误,这意味着我无法从 rsa-key 中删除我的密码,这正是我尝试使用 if 编写上述脚本的原因陈述。所以请不要告诉我使用 rsa 密钥。
回答by cxw
Your bash script is passing the expect
commands on the standard input of expect
. That is what the here-document<<EOD
does. However, expect
... expects its commands to be provided in a file, or as the argument of a -c
, per the man page. Three options are below. Caveat emptor; none have been tested.
您的 bash 脚本正在 .bashrcexpect
的标准输入上传递命令expect
。这就是here-document<<EOD
所做的。但是,expect
... 期望它的命令在文件中提供,或者作为 a 的参数-c
,根据手册页。下面是三个选项。买者自负; 没有经过测试。
Process substitutionwith here-document:
expect <(cat <<'EOD' spawn ... (your script here) EOD )
The
EOD
ends the here-document, and then the whole thing is wrapped in a<( )
process substitution block. The result is thatexpect
will see a temporary filename including the contents of your here-document.As @Aserre noted, the quotes in
<<'EOD'
mean that everything in your here-document will be treated literally. Leave them off to expand bash variables and the like inside the script, if that's what you want.EditVariable+here-document:
IFS= read -r -d '' expect_commands <<'EOD' spawn ... (your script here) interact EOD expect -c "${expect_commands// /;}"
Yes, that is a real newline after
//
- it's not obvious to me how to escape it. That turns newlines into semicolons, which the man pagesays is required.Thanks to this answerfor the
read
+heredoc combo.Shell variable
expect_commands=' spawn ... (your script here) interact' expect -c "${expect_commands// /;}"
Note that any
'
in the expect commands (e.g., afterid_rsa
) will need to be replaced with'\''
to leave the single-quote block, add a literal apostrophe, and then re-enter the single-quote block. The newline after//
is the same as in the previous option.
使用此处文档进行过程替换:
expect <(cat <<'EOD' spawn ... (your script here) EOD )
的
EOD
结束这里的文档,然后整个事情被包裹在一个<( )
进程替换块。结果是expect
将看到一个临时文件名,包括您的此处文档的内容。正如@Aserre 所指出的,引号
<<'EOD'
意味着您的此处文档中的所有内容都将按字面意思处理。如果这是您想要的,请不要使用它们以在脚本中扩展 bash 变量等。编辑变量+此处文档:
IFS= read -r -d '' expect_commands <<'EOD' spawn ... (your script here) interact EOD expect -c "${expect_commands// /;}"
是的,这是一个真正的换行符
//
- 我不知道如何逃避它。这会将换行符转换为分号,手册页说这是必需的。感谢这个答案为
read
+定界符组合。外壳变量
expect_commands=' spawn ... (your script here) interact' expect -c "${expect_commands// /;}"
请注意,
'
expect 命令中的任何内容(例如 afterid_rsa
)都需要替换为'\''
以离开单引号块,添加文字撇号,然后重新进入单引号块。后面的换行符//
与上一个选项相同。