如何在Expect脚本中发送带有$符号的密码

14

我有一个expect脚本,需要登录到远程系统并执行命令。这个脚本可以正常工作,但无法提供root帐户的密码。root密码包含一个美元符号,我似乎无法让它工作。以下是代码:

#!/usr/bin/expect
set timeout 3
set username "root"
set password "Pas$word"
set hostname [lindex $argv 0]
log_user 0

send_user "\n#####\n# $hostname\n#####\n"

spawn ssh -q -o StrictHostKeyChecking=no $username@$hostname

expect {
    timeout { send_user "\nFailed to get password prompt\n"; exit 1 }
    eof { send_user "\nSSH failure for $hostname\n"; exit 1 }
    "*assword"
}

send "$password\r"

expect {
    timeout { send_user "\nLogin failed. Password incorrect.\n"; exit 1}
    "*\$ "
}

send_user "\nPassword is correct\n"

expect "$ " { send "ls" }

我已经验证了,当提供的凭据密码不包含美元符号时可以工作,但我无法让它在root帐户上运行。它总是会产生“登录失败。密码不正确”超时错误。更改密码不是一个选项。我尝试在密码定义中提供\转义字符,像这样:

set password "Pas\$word"

我得到了相同的结果...你有什么想法,我错在哪里了吗?

谢谢

编辑 就像我说的,我已经尝试转义$字符。但为了澄清,我添加了一个打印语句,在脚本启动时验证变量是否正确地包含了密码...以下是更改内容:

set password "Pas\$word"
...
send_user "\n#####\n# $hostname\n#####\n"
send_user "Using password: $password\n"
...

这里是控制台输出:

njozwiak@ubuntu:~$ ./ssh_ls.sh 192.168.5.93

#####
# 192.168.5.93
#####
Using password: Pas$word

Login failed. Password incorrect.

在使用set时,无论在何处都要去掉引号。请查看我的答案。 - SSaikia_JtheRocker
1
我认为 set password {Pas$word} 应该足够了。使用 expect -d ssh-ls.sh 运行你的脚本,以查看后台发生了什么。 - glenn jackman
8个回答

9

尝试转义反斜杠,即

Pas$word

变成

Pas\\\$word

这是脚本编写中常见的问题(即使在PHP、Python中也有),字符串被反转义了两次甚至更多次!一个完整的例子是我如何在Bash脚本中使用SFTP和expect
#!/bin/bash
host=mysftp.dmz
port=22
username=john

/usr/bin/expect <<EOF
set timeout -1
spawn sftp -C -oPort=$port $username@$host
expect "password:"
send "Pas\\\$word\r"
expect "sftp>"
send "get data.txt\r"
expect "sftp>"
send "bye\r"
EOF

为什么我们需要三个反斜杠而不是一个? - zyy
@zyy:因为在这个过程中,字符串被解码了两次
  1. unescape("Pas\$word") => "Pas$word",
  2. unescape("Pas$word") => "Pas$word"
- John Mayor
谢谢,我会检查。 - zyy

8
我已经找到了一个临时解决方案。我相信这个问题早就被解决了,只是想提一下我是如何解决我的问题的:
实际密码:
Pas$word 将密码分配给变量:
set password {Pas\$word} 在TCL(或您代码中的expect)中,双括号{}之间的单词可以将括号内的内容设置为不进行替换,因此您的密码将被存储为:
Pas\$word
现在,在最后,当您通过expect发送密码 Pas\$word 时,它将被翻译为Pas$word,这是实际密码。
但问题是,如果密码是未知的,例如,密码在加密文件中或必须作为用户输入,则无法确定密码中有多少个 $ 符号。

临时的?这简直是天才! - jouell
太棒了!但是只是提醒那些试图避免所有bash符号的人,你不需要转义@ - ba11b0y

4

我尝试通过转义美元符号来使其工作,但是失败了。不过我通过使用\x来指定美元符号的十六进制值成功了。

设置密码为"Pas\x24word"


2

我发现这个问题是因为我也遇到了同样的问题,虽然这是一个老问题,但对于仍在寻找快速解决方案的人来说:

set CorrectedPassword [ string map -nocase { "\$" "\\\$" } $MyPassword ]

$CorrectedPassword随后被登录程序接受。-nocase不是必需的,但我发现默认包含它更安全。


1
我使用以下代码,它对我有效:
send \"Pas\\\$word\"

1

我曾经遇到过类似的问题,我想在expect脚本中传递带有"$"符号的fileName,以下方法对我有效:

filePath=$(echo -n $filePath | sed -e 's/\$/\\\$/g')

-1
我最近遇到了类似的问题,以下方法对我有用: $ PASS="pa\$\$word"; somecommand --user uname --password $PASS
注意双引号和分号。

  1. 你的解决方案是针对 pa$$word 而不是 pas$word
  2. 使用 expect 时,你需要将字符串转义两次:pas\\\$word
- John Mayor

-1

这肯定会有帮助 -

set username root
set password Pas\$word

去掉引号。

希望这对你有帮助。


没有引号和有引号的结果是一样的。登录失败,密码不正确。 - linsek
请注意,如果没有引号,密码在控制台输出中与带引号的密码相同。 "使用密码:Pas $ word" - linsek
@njozwiak - 设置用户名为root怎么样?那里也去掉引号了吗? - SSaikia_JtheRocker
@njozwiak - 我这么说是因为我刚刚在我的机器上尝试过,它的运行非常好。 :) - SSaikia_JtheRocker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接