如何在ruby脚本中隐藏从terminalinput的密码
我是新来的ruby。 我需要通过gets
命令接收密码作为input。
如何隐藏terminal中input的密码input,在gets
通话期间
“ 密码 ”是另一种select。
也可以使用核心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)
有一个名为highline的库,其工作原理是这样的:
require 'rubygems' require 'highline/import' password = ask("Enter password: ") { |q| q.echo = false } # do stuff with password
正如其他人提到的,你可以使用IO#noecho
Ruby> = 1.9。 如果你想要1.8的支持,你可以掏出内置的shell函数:
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
客户端)在提示符(例如$
/ "
/ '
/ etc)中传递了特殊的shell字符,你会遇到麻烦。理想情况下,提示string,然后Shellwords
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的情况有点不好, 它不允许反斜杠,除非你反斜杠两次:“反斜线字符'\'可能被用来删除下一个字符读取和连续行的任何特殊含义。 另外:“IFSvariables的值中的字符被用来将行分割成单词”。对于大多数小脚本来说,这应该是可以的,但是对于大型应用程序,您可能需要更强大的function。
我们可以通过卷起袖子来解决其中的一些问题,并用stty(1)
。 我们需要做什么的概要:
- 存储当前的terminal设置
- 回声的转动
- 打印提示并获取用户input
- 恢复terminal设置
当信号和/或exception中断时,我们还必须注意恢复terminal设置。 以下代码将正确处理作业控制信号(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
对于Ruby版本1.8(或Ruby <1.9),我使用了@Charles提到的读取 shell内build。
把代码刚好足以提示input用户名和密码,input时用户名将回显到屏幕上,但input的密码将是无声的。
userid = `read -p "User Name: " uid; echo $uid`.chomp passwd = `read -s -p "Password: " password; echo $password`.chomp
从Ruby 2.3.0开始,你可以使用如下的IO#getpass方法: STDIN.getpass("Password:")
http://ruby-doc.org/stdlib-2.3.0/libdoc/io/console/rdoc/IO.html#method-i-getpass