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

Posted

技术标签:

【中文标题】如何在 Expect 脚本中发送带有 $ 符号的密码【英文标题】:How to send a password with a $ symbol in Expect Script 【发布时间】:2013-07-29 12:47:18 【问题描述】:

我有一个期望脚本,我需要登录到远程系统并执行命令。除了向 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 帐户一起使用。它总是产生Login failed. Password incorrect 超时错误。更改密码不是一种选择。我试图在密码定义中提供\ 转义字符,如下所示:

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 的任何地方都去掉引号。查看我的答案。 我认为set password Pas$word 应该足够了。使用expect -d ssh-ls.sh 运行您的脚本,看看后台发生了什么。 【参考方案1】:

我为此找到了一个临时解决方案。我确定这个问题很久以前就解决了,只是提一下我是如何解决我的问题的:

实际密码:Pas$word

分配给变量密码:set password Pas\$word

在 TCL 中(或在您的代码中期望),在双括号 中分组单词会禁用括号内的替换,因此您的密码将存储为: Pas\$word 现在最后,当你通过expect发送密码时,Pas\$word会被翻译成Pas$word,也就是真正的密码。

但问题是如果密码未知,例如密码在加密文件中或必须作为用户输入。我一直在寻找这种我不知道密码在哪里以及有多少 $ sings 的情况。

【讨论】:

临时?这是天才! 天才!但是只是让那些试图逃避所有 bash 符号的人,你不需要逃避 @【参考方案2】:

尝试转义反斜杠,即

Pas$word

变成

Pas\\\$word

这是脚本(即使是 php、Python)中的一个常见问题,其中字符串被转义两次甚至更多次!

我如何在 Bash 脚本中将 expect 与 SFTP 一起使用的完整示例:

#!/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:因为在这个过程中“字符串被转义两次”: 1. unescape("Pas\\$word") => "Pas\$word ", 2. unescape("Pas\$word") => "Pas$word" 谢谢,我会查的。【参考方案3】:

我无法通过转义美元符号来完成这项工作。通过使用 \x 指定美元符号的十六进制值,我确实很幸运。

设置密码“Pas\x24word”

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

我有一个类似的问题,我想在期望脚本中传递带有“$”的文件名,并且以下对我有用

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

【讨论】:

【参考方案6】:

我在下面使用,它对我有用:

send \"Pas\\\$word\"

【讨论】:

【参考方案7】:

这绝对有帮助 -

set username root
set password Pas\$word

去掉引号。

希望这会有所帮助。

【讨论】:

无引号产生与带引号相同的结果。 Login failed. Password incorrect. 请注意,如果没有引号,则控制台输出中显示的密码与带有引号的密码相同。 "使用密码:Pas$word" @njozwiak - 设置用户名 root 怎么样?你也去掉了那里的引号吗? @njozwiak - 我这么说是因为我刚刚在我的机器上尝试过,它工作得很好。 :)【参考方案8】:

我最近遇到了类似的问题。这对我有用:

$ PASS="pa\$\$word"; somecommand --user unname --password $PASS

注意双引号和分号。

【讨论】:

1) 您的解决方案适用于 pa$$word,而不适用于 pas$word,并且 2) expect 您需要对字符串进行两次转义:pas\\\$word

以上是关于如何在 Expect 脚本中发送带有 $ 符号的密码的主要内容,如果未能解决你的问题,请参考以下文章

无法在 bash 脚本期望中发送长命令

在启动的 telnet 会话中使用期望脚本

如何将带有管道符号的多个参数传递到bash脚本案例语句中

如何在bash shell脚本中使用expect

shell脚本之通过发送带 字符串或expect脚本实现交互输入自动化

expect脚本在Linux下是如何使用的