我是红宝石的新手。我需要通过gets
命令接收密码作为输入。
在gets
通话期间,如何隐藏在终端中键入的密码输入
Answers:
一个人也可以使用核心红宝石。
$ 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'
代码。通常比任何宝石选项都要好。
tmp.rb:2:in 'noecho': Bad file descriptor (Errno::EBADF) from tmp.rb:2:in <main>
正如其他人提到的,您可以将IO#noecho
Ruby> = 1.9用于。如果您希望支持1.8,则可以使用read
内置的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
)在提示中传递特殊的shell字符(例如$
/ "
/ '
/ etc),则会遇到麻烦。理想情况下,应在将提示字符串传递到外壳程序之前对其进行转义。不幸的是,Shellwords
在Ruby 1.8中不可用。幸运的是,您可以很容易地自己(特别是)反向移植相关位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