在 Bash shell 中获取并使用带有特殊字符的密码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41782202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 15:38:12  来源:igfitidea点击:

Get and use a password with special characters in Bash shell

linuxbashshellquoting

提问by Cheloute

I'm getting some troubles to use a password with special characters such as $ in a bashshell script.

我在bashshell 脚本中使用带有特殊字符(例如 $)的密码时遇到了一些麻烦。

My shell script is :

我的 shell 脚本是:

read -s -p "Password : " bindDNPass
ldapadd -H ldap://localhost -x -w $bindDNPass -D "dn=cn=Admin" -f /tmp/file.ldif

And the password could be something like $Something18$.

密码可能类似于 $Something18$。

Well, the command

嗯,命令

ldapadd -H ldap://localhost -x -W -D "dn=cn=Admin" -f /tmp/file.ldif` 

asks for my $Something18$, and works fine.

要求我的$Something18$,并且工作正常。

But if I try

但如果我尝试

ldapadd -H ldap://localhost -x -w $Something18$ -D "dn=cn=Admin" -f /tmp/file.ldif

it doesn't work. I guess it's trying to resolve the variable $Something18,so I tried with \$Something18$, \$Something18\$,\\\$Something18$, ... but it keeps on failing...

它不起作用。我想它正在尝试解析变量,$Something18,所以我尝试使用\$Something18$, \$Something18\$,\\\$Something18$, ... 但它一直失败......

How can I do? (Without changing my password...)

我能怎么做?(无需更改密码...)

回答by Gordon Davisson

I see two potential problems with how you're reading and using the password:

我发现您阅读和使用密码的方式有两个潜在问题:

  • When you use the readcommand withoutthe -roption, it'll try to interpret escape (backslash) sequences, which may cause trouble.
  • When you use a variable withoutwrapping it in double-quotes, it'll try to split the value into separate words and also try to expand any wildcards into a list of matching filenames. This can cause massiveconfusion, so you should almost always double-quote variable references.
  • 当您使用read命令没有-r选项,它会试图解释逃生(反斜杠)序列,这可能会造成麻烦。
  • 当您使用一个变量而不用双引号括起来时,它会尝试将值拆分为单独的单词,并尝试将任何通配符扩展为匹配文件名的列表。这可能会导致大量混乱,因此您几乎总是应该双引号引用变量。

Fixing these potential problems gives this script snippet:

修复这些潜在问题给出了这个脚本片段:

read -rs -p "Password : " bindDNPass
ldapadd -H ldap://localhost -x -w "$bindDNPass" -D "dn=cn=Admin" -f /tmp/file.ldif

...But, while you should do both of these mods to make your script more robust, neither of these will change how it handles the password $Something18$. In fact, when I tried your original snippet with that password, it got passed to ldapaddcorrectly. If your actual password has some other special characters in it (or you've played with the value of IFS), these might help; otherwise, there's something else going on.

...但是,虽然您应该同时执行这两个 mod 以使您的脚本更健壮,但这些都不会改变它处理密码的方式$Something18$。事实上,当我用那个密码尝试你的原始片段时,它被ldapadd正确地传递了。如果您的实际密码中包含一些其他特殊字符(或者您使用了 的值IFS),这些可能会有所帮助;否则,还有其他事情发生。

If your password still doesn't work after these fixes, try putting set -xbefore the ldapaddcommand (and set +xafter) so it'll print what's actually being passed to ldapadd. Well, it'll print it in a possibly confusing form: it'll print an equivalent commandto what's actually being executed, which means it'll add quotes and/or escapes to the password parameter as necessary so that you could run that command and it'll do the same thing. When I tried it with $Something18$, it printed:

如果您的密码在这些修复后仍然不起作用,请尝试将其放在命令set -x之前ldapadd(和set +x之后),以便它打印实际传递给ldapadd. 好吧,它会以一种可能令人困惑的形式打印它:它会打印一个与实际正在执行的命令等效的命令,这意味着它会根据需要向密码参数添加引号和/或转义符,以便您可以运行该命令它会做同样的事情。当我用 尝试它时$Something18$,它打印:

+ ldapadd -H ldap://localhost -x -w '$Something18$' -D dn=cn=Admin -f /tmp/file.ldif

...where the single-quotes mean that what's inside them is passed directly, with no parsing. It could also have printed any of the following equivalent commands:

...其中单引号表示其中的内容直接传递,无需解析。它还可以打印以下任何等效命令:

+ ldapadd -H ldap://localhost -x -w $Something18$ -D dn=cn=Admin -f /tmp/file.ldif
+ ldapadd -H ldap://localhost -x -w "$Something18$" -D dn=cn=Admin -f /tmp/file.ldif
+ ldapadd -H ldap://localhost -x -w $'$Something18$' -D dn=cn=Admin -f /tmp/file.ldif

so you have to take what it prints, and figure out how that'd be parsed by bash, in order to figure out what's actually being passed to ldapadd. But at least it'll give you some information about what's actually happening.

所以你必须接受它打印的内容,并弄清楚 bash 如何解析它,以便找出实际传递给ldapadd. 但至少它会给你一些关于实际发生的事情的信息。

Oh, and you may notice that the DN argument isn't being double-quoted. That's because it doesn't contain any special characters, so the double-quotes aren't doing anything, so it just left them off.

哦,您可能会注意到 DN 参数没有被双引号引用。那是因为它不包含任何特殊字符,所以双引号没有做任何事情,所以它只是把它们放在一边。

回答by Inian

Put it in double-quotes and escape the $symbol avoid special interpretation from the shell,

把它放在双引号中并转义$符号,避免特殊解释shell

ldapadd -H ldap://localhost -x -w "$Something18$" -D "dn=cn=Admin" -f /tmp/file.ldif

(or) [more recommended]

(或) [更多推荐]

Enclose it within single-quote to let the shell treat it as a literal string without expanding it,

将它括在单引号内,让 shell 将其视为文字字符串而不展开它,

ldapadd -H ldap://localhost -x -w '$Something18$' -D "dn=cn=Admin" -f /tmp/file.ldif

From the man bashpage,

man bash页面,

Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, , \, and, when history expansion is enabled, !. The characters $ and retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or .A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.

双引号中的字符会保留引号内所有字符的字面值但 $、 、\ 和启用历史扩展时的 ! 除外。字符 $ 和在双引号内保留其特殊含义。该反斜杠只有后面当由下列字符特殊意义:$,`,”,\,或。双引号可以包含双引号内的前面加一个反斜杠它被引用启用如果,历史扩展将执行除非出现在双引号中的 ! 使用反斜杠进行转义。不会删除 ! 之前的反斜杠。