Как уже упоминалось, вы можете использовать IO#noecho
для Ruby> = 1,9. Если вам нужна поддержка 1.8, вы можете использовать встроенную функцию оболочки 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
) передадите специальные символы оболочки в приглашении (например, * 1018) * / "
/ '
/ и т.д.). В идеале вы должны экранировать строку приглашения, прежде чем передавать ее в оболочку. К сожалению, 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