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


131

对于那些想回复我应该使用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脚本。我之所以使用bash,是因为我使用了可以选择要连接到的设备的菜单。

谢谢


49
请参阅第一条线:对于那些谁想要回复,我应该使用SSH密钥请忌讳
马克斯

54
我会编辑您的第一行,使其更加友好。您可能会考虑类似“由于限制,我根本无法使用SSH密钥,我必须找到一种使其与Expect一起工作的方法”。您应该希望人们会自然地好奇为什么您不使用键,而只是想提供帮助:) @Ignacio并不建议您使用键,他只是在确认它是一个约束而不是疏忽。
Tim Post

在这种情况下,我会尝试使用kermit。它具有非常强大的脚本语言columbia.edu/kermit/skermit.html#scripts
f3xy

Answers:


86

混合bash和Expect不是获得所需效果的好方法。我会尝试仅使用Expect:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
#use 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 }'

这将等待进入并返回(暂时)交互式会话。


1
很好,谢谢。如果我想通过SSH登录后键入命令,该怎么办?
最大

该脚本应返回具有登录用户的无效外壳。我不明白问题。如果您绝对要在bash中使用相同的脚本,请查看已编辑的条目。
PiotrKról2011年

用同样的方法提示,当我发送密码,我想送系统命令,一旦登陆,
最大

Samlple代码已添加到上面的帖子中。当然,这将一直有效,直到my_commandX不更改返回的提示为止,如果发生这种情况,则应该更改提示变量。
PiotrKról2011年

@pietrushnic您能解释一下为什么使用“ interact -o -nobuffer -re $ prompt return”而不是“ expect $ prompt”吗?后者看起来更常用..
理查德

53

最简单的方法是使用sshpass。这在Ubuntu / Debian仓库中可用,您不必处理将期望与bash集成的问题。

一个例子:

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

上面的命令可以与bash脚本轻松集成。

注意:请阅读“ 安全注意事项”部分,man sshpass以全面了解安全隐患。


我不知道这是否是一个很好的解决方案,但是它确实简化了很多。谢谢
erikbwork 2015年

9
从安全角度来看非常危险-命令行参数可以由系统上的任何其他进程读取。可以覆盖它们,并希望sshpass这样做,但是即使这样,在任何/每个进程都可以看到密码的情况下,仍有一段时间仍会启动它。
查尔斯·达菲

1
@CharlesDuffy当然,您是正确的。sshpass用于具有简单测试脚本的情况,这些脚本在安全不是重点的本地网络环境中执行。实际上,其中有一个部分man sshpass解释了有关安全注意事项的整个部分。添加此答案,谢谢。
dotnix

@ erikb85通常,程序包会为您完成所有肮脏的工作,但是,在所有情况下,这些脚本都是为该用途而构建的,因此比添加您自己的工作更好。此评论是关于不要重新发明轮子。仅在还没有人处理过的情况下处理硬物。sshpass这是一个很好的功能。
m3nda 2015年

2
为了完整起见,我提到“ man sshpass”会向潜在用户提供适当的安全警告,并指出“ -p”是使用它的最不安全的方式,并提供了“ -e”选项以通过环境变量获取密码,至少可以使它脱离命令行。
罗恩·伯克

22

在您的EOD之前添加“ interact”期望命令:

#!/bin/bash

read -s PWD

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

这应该使您可以与远程计算机进行交互,直到注销为止。然后,您将重返bash。


它进入并立即退出。印有“你不在”的字样。
伊曼纽尔

8
我已将“ interact”和“ EOD”替换为“ expect eof”,它对我有用。这是在Mac上。
伊曼纽尔

2
此页面上的答案均不适合我,但@Emmanuel的使用建议expect eof解决了该问题。
moertel

'从中删除usr@$myhost.example.com'它,它应该可以工作。也许您需要替换\n\r,但YMMV
Tino

19

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

#!/usr/bin/expect

set timeout 20

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

eval spawn $cmd
expect "Password:"
send "$password\r";
interact

将其放在/usr/bin/exp,则可以使用:

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

做完了!


expect "assword:"你的意思是expect "password:"
用户

1
@user "assword"将同时匹配Passwordpassword
Ferdinand.kraft

8

还要确保使用

send -- "$PWD\r" 

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

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


8

一个简单的期望脚本

远程登录

    #!/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>

7

使用帮助程序工具fd0ssh(来自hxtools,而不是pmt),它可以正常工作,而无需从ssh程序获得特定提示。


这很棒!要使其运行起来有点困难(至少在ubuntu服务器中),但可以正常运行!我们进行的配置: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port user@yourserver.com & 谢谢!
JP Illanes

1
这比在命令行上通过密码安全得多sshpass
查尔斯·达菲

5

我发现使用bash脚本中的期望脚本有用的另一种方法如下。

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


您不需要-这里,因为如果不带参数调用它,则默认情况下expect是从这里读取的stdin。但是,如果您想在不使用命令提示符的情况下以交互方式运行它(expectvs. expect -),或者在您执行expect -f "$@"第一个参数应为文件的操作(即使它看起来像是一个选项,以开头-)的情况下很有用。在这种情况下,如果$1(给定的文件)是-从读取stdin
蒂诺

1

sshpass如果您尝试在Makefile中的Sublime Text构建目标中使用它,则会损坏该文件。代替sshpass您可以使用passh https //github.com/clarkwang/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. /ubuntu/87449/how-to-disable-strict-host-key-checking-in-ssh
  3. https://linuxcommando.blogspot.com/2008/10/how-to-disable-ssh-host-key-checking.html
  4. /server/330503/scp-without-known-hosts-check
  5. https://debian-administration.org/article/587/pam_mount_and_sshfs_with_password_authentication
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.