我是ruby的新手。我需要通过gets
命令接收密码输入。
在gets
调用期间,如何隐藏在终端中键入的密码输入?
我是ruby的新手。我需要通过gets
命令接收密码输入。
在gets
调用期间,如何隐藏在终端中键入的密码输入?
也可以使用核心 Ruby。
$ ri IO.noecho
(from ruby core)
------------------------------------------------------------------------------
io.noecho {|io| }
------------------------------------------------------------------------------
Yields self with disabling echo back.
STDIN.noecho(&:gets)
will read and return a line without echo back.
对于1.9.3及以上版本,这需要您在代码中添加require 'io/console'
。
require 'io/console'
text = STDIN.noecho(&:gets)
require 'io/console'
。通常比任何宝石选项都要好。 - iccotmp.rb:2:in 'noecho': Bad file descriptor (Errno::EBADF) from tmp.rb:2:in <main>
- Chloe有一个名为highline的库,其工作方式如下:
require 'rubygems'
require 'highline/import'
password = ask("Enter password: ") { |q| q.echo = false }
# do stuff with password
require 'io/console'
password = STDIN.noecho(&:gets).chomp
对于1.9.3及以上版本,需要在您的代码中添加require 'io/console'
。
Ruby "密码"是另一种选择。
从Ruby 2.3.0版本开始,您可以使用IO#getpass
方法,如下所示:
require 'io/console'
password = STDIN.getpass("Password:")
请参阅标准库文档中的getpass方法。
STDIN.getpass.chomp
解决了这个问题 @ShadSterling - Olivier Lacangetpass
在输入字符串上内部调用chomp!
,所以它比其他答案更好。请参考文档:
返回的字符串中移除了终止读取行的换行符,请参阅String#chomp!。
- Olivier Lacan如其他人所提到的,您可以在 Ruby >= 1.9 中使用 IO#noecho
。如果您想要支持 1.8 版本,您可以调用内置的 shell 函数 read
:
begin
require 'io/console'
rescue LoadError
end
if STDIN.respond_to?(:noecho)
def get_password(prompt="Password: ")
print prompt
STDIN.noecho(&:gets).chomp
end
else
def get_password(prompt="Password: ")
`read -s -p "#{prompt}" password; echo $password`.chomp
end
end
现在获取密码就像这么简单:
@password = get_password("Enter your password here: ")
注意:在使用上面的read
实现时,如果您或者get_password
的另一个客户端在提示符中传递特殊的shell字符(例如$
/"
/'
/etc),则会遇到麻烦。理想情况下,在将提示字符串传递给shell之前,您应该对其进行转义。不幸的是,Ruby 1.8中没有可用的Shellwords
。幸运的是,可以轻松地将相关部分回退(具体来说,是shellescape
)。有了这个,您可以进行如下微小的修改: def get_password(prompt="Password: ")
`read -s -p #{Shellwords.shellescape(prompt)} password; echo $password`.chomp
end
在下面的评论中,我提到了使用 read -s -p
存在一些问题:
嗯,1.8 版本有点不太好用;它不允许使用反斜杠,除非你输入两个反斜杠:“反斜杠字符 \ 可用于去除下一个字符的特殊含义以及行连续符。IFS 变量值中的字符用于将行分割成单词。”这对于大多数小脚本来说可能已足够,但对于更大型的应用程序,你可能需要更健壮的东西。
我们可以通过动手使用 stty(1)
来解决其中的一些问题。我们需要做以下工作:
同时,我们还必须注意在信号和/或异常中断时恢复终端设置。以下代码将正确处理作业控制信号(SIGINT/SIGTSTP/SIGCONT),同时仍然与任何现有信号处理程序配合良好:
require 'shellwords'
def get_password(prompt="Password: ")
new_sigint = new_sigtstp = new_sigcont = nil
old_sigint = old_sigtstp = old_sigcont = nil
# save the current terminal configuration
term = `stty -g`.chomp
# turn of character echo
`stty -echo`
new_sigint = Proc.new do
`stty #{term.shellescape}`
trap("SIGINT", old_sigint)
Process.kill("SIGINT", Process.pid)
end
new_sigtstp = Proc.new do
`stty #{term.shellescape}`
trap("SIGCONT", new_sigcont)
trap("SIGTSTP", old_sigtstp)
Process.kill("SIGTSTP", Process.pid)
end
new_sigcont = Proc.new do
`stty -echo`
trap("SIGCONT", old_sigcont)
trap("SIGTSTP", new_sigtstp)
Process.kill("SIGCONT", Process.pid)
end
# set all signal handlers
old_sigint = trap("SIGINT", new_sigint) || "DEFAULT"
old_sigtstp = trap("SIGTSTP", new_sigtstp) || "DEFAULT"
old_sigcont = trap("SIGCONT", new_sigcont) || "DEFAULT"
print prompt
password = STDIN.gets.chomp
puts
password
ensure
# restore term and handlers
`stty #{term.shellescape}`
trap("SIGINT", old_sigint)
trap("SIGTSTP", old_sigtstp)
trap("SIGCONT", old_sigcont)
end
\
可以用于删除下一个读取字符的任何特殊含义和行延续。”另外:“IFS变量值中的字符用于将行拆分为单词。”这对于大多数小脚本来说可能还好,但对于更大的应用程序,您可能需要使用更强大的工具。 - Charles对于Ruby版本1.8(或Ruby < 1.9),我使用了read shell内置命令,如@Charles所提到的。
只需放置足够的代码即可提示用户名和密码,其中用户名将在输入时回显到屏幕上,但输入的密码将保持沉默。
userid = `read -p "User Name: " uid; echo $uid`.chomp
passwd = `read -s -p "Password: " password; echo $password`.chomp