Ich bin neu in Ruby. Ich muss ein Passwort als Eingabe über einen gets
Befehl erhalten.
Wie verstecke ich die im Terminal während des gets
Anrufs eingegebene Passworteingabe?
Antworten:
require 'io/console'
password = STDIN.noecho(&:gets).chomp
Für 1.9.3 (und höher) müssen Sie require 'io/console'
Ihren Code hinzufügen .
Ruby " Passwort " ist eine weitere Alternative.
Man kann auch Kern Rubin verwenden.
$ 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.
Für 1.9.3 (und höher) müssen Sie require 'io/console'
Ihren Code hinzufügen .
require 'io/console'
text = STDIN.noecho(&:gets)
require 'io/console'
Ihren Code hinzufügen . Viel besser als jede Edelsteinoption normalerweise.
tmp.rb:2:in 'noecho': Bad file descriptor (Errno::EBADF) from tmp.rb:2:in <main>
Es gibt eine Bibliothek namens Highline, die so funktioniert:
require 'rubygems'
require 'highline/import'
password = ask("Enter password: ") { |q| q.echo = false }
# do stuff with password
Wie die anderen erwähnen, können Sie IO#noecho
für Ruby> = 1.9 verwenden. Wenn Sie Unterstützung für 1.8 read
wünschen , können Sie die integrierte Shell-Funktion verwenden:
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
Jetzt ist es so einfach, ein Passwort zu erhalten wie:
@password = get_password("Enter your password here: ")
Hinweis: Bei der oben verwendeten Implementierung read
treten Probleme auf, wenn Sie (oder ein anderer Client von get_password
) spezielle Shell-Zeichen in der Eingabeaufforderung (z. B. $
/ "
/ '
/ etc) weitergeben. Im Idealfall sollten Sie die Eingabeaufforderungszeichenfolge maskieren, bevor Sie sie an die Shell weitergeben. Ist Shellwords
in Ruby 1.8 leider nicht verfügbar. Glücklicherweise ist es einfach, die relevanten Bits selbst (speziell shellescape
) zurück zu portieren . Damit können Sie diese geringfügige Änderung vornehmen:
def get_password(prompt="Password: ")
`read -s -p #{Shellwords.shellescape(prompt)} password; echo $password`.chomp
end
Ich erwähnte ein paar Probleme mit der Verwendung von read -s -p
in einem Kommentar unten:
Nun, der 1.8-Fall ist ein bisschen ruckelig; Backslashes sind nicht zulässig, es sei denn, Sie drücken zweimal Backslash: "Das Backslash-Zeichen" \ "kann verwendet werden, um spezielle Bedeutungen für das nächste gelesene Zeichen und für die Fortsetzung der Zeile zu entfernen." Außerdem: "Die Zeichen im Wert der IFS-Variablen werden verwendet, um die Zeile in Wörter aufzuteilen." Dies sollte wahrscheinlich für die meisten kleinen Skripte in Ordnung sein, aber für größere Anwendungen möchten Sie wahrscheinlich etwas Robusteres.
Wir können einige dieser Probleme beheben, indem wir die Ärmel hochkrempeln und dies mit aller Kraft tun stty(1)
. Ein Überblick darüber, was wir tun müssen:
Wir müssen auch darauf achten, die Terminaleinstellungen wiederherzustellen, wenn sie durch Signale und / oder Ausnahmen unterbrochen werden. Der folgende Code verarbeitet Jobsteuerungssignale (SIGINT / SIGTSTP / SIGCONT) ordnungsgemäß, während er weiterhin mit allen vorhandenen Signalhandlern spielt:
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
Ab Ruby Version 2.3.0 können Sie die folgende IO#getpass
Methode verwenden:
require 'io/console'
password = STDIN.getpass("Password:")
Siehe die getpass- Methode in der Standardbibliotheksdokumentation.
Für Ruby Version 1.8 (oder Ruby <1.9) habe ich die von @Charles erwähnte Read Shell verwendet.
Wenn Sie den Code eingeben, der gerade ausreicht, um zur Eingabe von Benutzername und Kennwort aufzufordern, wobei der Benutzername während der Eingabe auf dem Bildschirm angezeigt wird, das eingegebene Kennwort jedoch stumm bleibt.
userid = `read -p "User Name: " uid; echo $uid`.chomp
passwd = `read -s -p "Password: " password; echo $password`.chomp