我正在尝试在Bash脚本中使用Expect提供SSH密码。提供密码是可行的,但是我并没有像应该的那样最终进入SSH会话。它回到了Bash。
我的脚本:
#!/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密钥的人,请弃权。

评论

请参阅第一行:对于那些想回复我应该使用SSH密钥的人,请弃权

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

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

#1 楼

混合Bash和Expect不是达到预期效果的好方法。我只尝试使用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,然后返回(片刻)交互式会议。

评论


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

–最大
2011年1月25日13:28

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

–彼得·克罗尔(PiotrKról)
2011-1-25 13:49

与提示时发送密码的方式相同,登录后我想发送系统命令。

–最大
2011年1月26日14:43

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

–彼得·克罗尔(PiotrKról)
2011-1-26 15:37

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

–理查德
2012年9月20日11:12

#2 楼

最简单的方法是使用sshpass。这在Ubuntu / Debian存储库中可用,您不必处理将期望与Bash集成的情况。
示例:
sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

上述命令可以轻松地与Bash脚本集成。
注意:请阅读man sshpass中的“安全注意事项”部分,以全面了解安全隐患。

评论


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

–erikbwork
15年2月10日在18:52

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

–查尔斯·达菲(Charles Duffy)
15年5月21日在22:45



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

– dotnix
15年5月22日在17:16



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

– m3nda
2015年6月5日19:36

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

–罗恩·伯克(Ron Burk)
16年4月14日在16:27

#3 楼

在EOD之前添加'interact'Expect命令:
#!/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。

评论


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

–伊曼纽尔
2013年4月30日14:03在

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

–伊曼纽尔
13年4月30日在14:08

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

– moertel
17-10-9在12:21



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

– Tino
18年6月12日在18:32

#4 楼

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

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

完成!

评论


期望“密码:”是指期望“密码:”吗?

–用户
19年4月28日在7:45

@user“ assword”将同时匹配密码和密码。

– Ferdinand.kraft
19年4月4日在0:36

带有两个参数的scp也很棒。当然,ssh也可以有2个参数。

– Timo
11月7日19:37

#5 楼

另外,请务必使用
send -- "$PWD\r"

,否则以破折号(-)开头的密码将会失败。
以上内容不会将以破折号开头的字符串解释为发送命令。

#6 楼

一个简单的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>
 


#7 楼

使用辅助工具fd0ssh(来自hxtools,而非pmt)。它可以正常工作,而无需期待来自ssh程序的特定提示。

评论


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

– JP Illanes
2011年11月2日23:54



与sshpass相比,比在命令行上传递密码安全得多。

–查尔斯·达菲(Charles Duffy)
15年5月21日在22:46

#8 楼

我发现使用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...

评论


您不需要-这里,因为如果您不带参数调用它,则默认情况下,它会从stdin中读取期望值。但是,如果您希望在不使用命令提示符的情况下以交互方式运行它(期望与期望-),或者在执行期望-f“ $ @”之类的操作时,即使第一个参数看起来像一个文件,它也很有用,选项(以-开头)。在这种情况下,如果$ 1(给定的文件)为-这将从stdin中读取。

– Tino
18年6月12日在18:29

#9 楼

如果您尝试在Makefile的Sublime Text构建目标中使用它,则会损坏sshpass。代替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

参考文献:

在SSH连接中使用Expect脚本发送密码的命令不起作用
如何在ssh中禁用严格的主机密钥检查?
如何禁用SSH主机密钥检查
scp,而无需known_hosts检查
通过密码认证的pam_mount和sshfs