在 Bash 脚本中使用 Expect 为 SSH 命令提供密码

我尝试在 Bash 脚本中使用 expect来提供 SSH 密码。提供密码可以工作,但是我不会像应该的那样在 SSH 会话中结束。回到巴斯身上。

我的剧本:

#!/bin/bash


read -s PWD


/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n"
EOD
echo "you're out"

我的脚本输出:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

我希望有我的 SSH 会话,只有当我退出时,才能返回到我的 Bash 脚本。

我之所以在 expect之前使用 Bash 是因为我必须使用一个菜单。我可以选择连接到哪个单元/设备。

对于那些想要回复说我应该使用 SSH 密钥的人,请弃权。

443300 次浏览

使用辅助工具 fd0ssh(来自 hxtools、 Ubuntu 源代码OpenSUSE 源代码,而不是 pmt)。它不需要从 ssh程序中得到特定的提示就可以工作。

它也“比像 sshpass 那样在命令行上传递密码要安全得多”(- comments by Charles Duffy)。

混合 Bash 和 Expect 并不是达到预期效果的好方法:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com


# Use the correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Bash 的示例解决方案可以是:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'

这将等待 Enter,然后返回(一会儿)交互式会话。

在爆炸物处理前添加“交互”Expect 命令:

#!/bin/bash


read -s PWD


/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send -- "$PWD\r"
interact
EOD
echo "you're out"

这应该可以让您在注销之前与远程计算机进行交互。

最简单的方法是使用 小意思。这在 Ubuntu/Debian存储库中可用,您不必处理与 Bash 的集成。

举个例子:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

上面的命令可以很容易地与 Bash 脚本集成。

注意: 请阅读 man sshpass中的 保安考虑部分,以便充分理解安全隐患。

还要确保使用

send -- "$PWD\r"

相反,以破折号(-)开头的密码将失败,否则。

以上代码不会将以破折号开头的字符串解释为 send 命令的选项。

我发现使用来自 Bash 脚本的 很小 Expect 脚本的另一种有用方法如下所示。

...
Bash script start
Bash commands
...
expect - <<EOF
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
More Bash commands
...

这是因为 ...If the string "-" is supplied as a filename, standard input is read instead...

在为这个问题寻找答案几个月后,我终于找到了一个真正最好的解决方案: 写一个简单的脚本。

#!/usr/bin/expect


set timeout 20


set cmd [lrange $argv 1 end]
set password [lindex $argv 0]


eval spawn $cmd
expect "assword:"   # matches both 'Password' and 'password'
send -- "$password\r"; # -- for passwords starting with -, see https://stackoverflow.com/a/21280372/4575793
interact

把它放到 /usr/bin/exp,然后你可以使用:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

成交!

一个简单的 Expect 脚本:

文件 Remotelogin.exp

    #!/usr/bin/expect
set user [lindex $argv 1]
set ip [lindex $argv 0]
set password [lindex $argv 2]
spawn ssh $user@$ip
expect "password"
send "$password\r"
interact

例如:

./Remotelogin.exp <ip> <user name> <password>

如果您尝试在一个 崇高的文字构建目标、一个 Makefile 中使用它,那么 sshpass就会被破坏。不是 sshpass而是 你可以使用 passh

有了 sshpass,你可以做到:

sshpass -p pa$$word ssh user@host

有了 passh,你可以做到:

passh -p pa$$word ssh user@host

注意: 不要忘记使用 -o StrictHostKeyChecking=no。否则,连接将在您第一次使用它时挂起。例如:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

参考文献:

  1. 在 SSH 连接中使用 Expect 脚本发送密码命令不起作用
  2. 如何在 ssh 中禁用严格的主机密钥检查?
  3. 如何禁用 SSH 主机密钥检查
  4. 没有 known _ hosts 检查的 scp
  5. 具有密码身份验证的 pam _ mount 和 sshfs