Как я могу ввести пароль с помощью Perl и заменить символы на «*»?

У меня есть сценарий Perl, который требует от пользователя ввода пароля. Как я могу отображать только «*» вместо символа, который вводит пользователь, когда он его печатает?

Я использую Windows XP/Vista.


person Matthew Farwell    schedule 31.03.2009    source источник


Ответы (7)


Вы можете поиграть с Term::ReadKey. Вот очень простой пример с некоторым обнаружением клавиши возврата и удаления. Я тестировал его на Mac OS X 10.5, но согласно руководству по ReadKey он должно работать под виндой. В руководстве указано, что в Windows при использовании неблокирующего чтения (ReadKey(-1)) произойдет сбой. Вот почему я использую ReadKey(0), который в основном getc (подробнее о getc в руководство по libc).

#!/usr/bin/perl                                                                                                                                                                                                

use strict;                                                                                                                                                                                                    
use warnings;                                                                                                                                                                                                  
use Term::ReadKey;                                                                                                                                                                                             

my $key = 0;                                                                                                                                                                                                   
my $password = "";                                                                                                                                                                                             

print "\nPlease input your password: ";                                                                                                                                                                        

# Start reading the keys                                                                                                                                                                                       
ReadMode(4); #Disable the control keys                                                                                                                                                                         
while(ord($key = ReadKey(0)) != 10)                                                                                                                                                                            
# This will continue until the Enter key is pressed (decimal value of 10)                                                                                                                                      
{                                                                                                                                                                                                              
    # For all value of ord($key) see http://www.asciitable.com/                                                                                                                                                
    if(ord($key) == 127 || ord($key) == 8) {                                                                                                                                                                   
        # DEL/Backspace was pressed                                                                                                                                                                            
        #1. Remove the last char from the password                                                                                                                                                             
        chop($password);                                                                                                                                                                                       
        #2 move the cursor back by one, print a blank character, move the cursor back by one                                                                                                                   
        print "\b \b";                                                                                                                                                                                         
    } elsif(ord($key) < 32) {                                                                                                                                                                                  
        # Do nothing with these control characters                                                                                                                                                             
    } else {                                                                                                                                                                                                   
        $password = $password.$key;                                                                                                                                                                            
        print "*(".ord($key).")";                                                                                                                                                                              
    }                                                                                                                                                                                                          
}                                                                                                                                                                                                              
ReadMode(0); #Reset the terminal once we are done                                                                                                                                                              
print "\n\nYour super secret password is: $password\n";   
person Pierre-Luc Simard    schedule 31.03.2009
comment
Это не работает под Windows. Он работает нормально, пока вы не нажмете клавишу ввода, когда вам нужно нажать ее четыре раза, чтобы она среагировала. Если вы используете ReadMode(2), то он работает нормально, но не выдает эха, пока вы не нажмете return. Не отображать * может быть приемлемой альтернативой - person Matthew Farwell; 31.03.2009
comment
Это не работает в Windows, потому что десятичное значение ascii клавиши Enter или Return равно 13 (CR: возврат каретки). Как только вы замените строку while(ord($key = ReadKey(0)) != 10) на while(ord($key = ReadKey(0)) != 13), она будет работать лучше :) - person Damien; 20.06.2011
comment
Возможно, вы также захотите проверить наличие \x03 (^C); Кроме того, вы, вероятно, захотите выдать \b \b только в том случае, если длина ($ пароль) › 0 или на основе возвращаемого значения Chop() (чтобы избежать стирания подсказки, если пользователь продолжает возвращаться) - person vladr; 17.09.2015
comment
1. Дэмиен прав: работает отлично под Windows, если добавить 13 для проверки ключа. 2. Владр: не нужно тестировать ни на ^C под Windows, ни на ^Break. ReadKey кажется невосприимчивым к этим прерываниям. Реализовал ваши идеи о \b... w/length(pwd). Идеально. 3. Все остальные модули IOPromp[er] и подобные не работают под Windows (7/64 и 10/64). Это решение является единственным. - person Gilles Maisonneuve; 23.11.2020

Раньше я использовал для этого IO::Prompt.

use IO::Prompt;
my $password = prompt('Password:', -e => '*');
print "$password\n";
person Peter Stuifzand    schedule 02.04.2009
comment
СТАТУС: этот модуль больше не поддерживается. Вместо этого используйте модуль IO::Prompter. - person reinierpost; 11.11.2014

Если вы не хотите использовать какие-либо пакеты... Только для UNIX

system('stty','-echo');
chop($password=<STDIN>);
system('stty','echo');
person Community    schedule 10.02.2010
comment
chomp будет лучше, чем chop - person Keith Thompson; 11.07.2013

Вы должны взглянуть либо на Term::ReadKey, либо на Win32::Console. Вы можете использовать эти модули для чтения отдельных нажатий клавиш и выдачи «*» или чего-то еще.

person innaM    schedule 31.03.2009

Опираясь на программу Пьера-Люка, мы добавили некоторый контроль над обратной косой чертой. При этом вы не можете постоянно нажимать обратную косую черту:

sub passwordDisplay() {
    my $password = "";
    # Start reading the keys
    ReadMode(4); #Disable the control keys
    my $count = 0;
    while(ord($key = ReadKey(0)) != 10) {
            # This will continue until the Enter key is pressed (decimal value of 10)
            # For all value of ord($key) see http://www.asciitable.com/
            if(ord($key) == 127 || ord($key) == 8) {
                    # DEL/Backspace was pressed
                    if ($count > 0) {
                            $count--;
                            #1. Remove the last char from the password
                            chop($password);
                            #2 move the cursor back by one, print a blank character, move the cursor back by one
                            print "\b \b";
                    }
            }
            elsif(ord($key) >= 32) {
                    $count++;
                    $password = $password.$key;
                    print "*";
            }
    }
    ReadMode(0); #Reset the terminal once we are done
    return $password;
}
person Hany    schedule 30.08.2012
comment
Нет необходимости в $count, подойдет length($password). - person vladr; 17.09.2015

с помощью программы Пьера-Люка

# Start reading the keys                                                                                                                                                                                       
ReadMode(4); #Disable the control keys                                                                                                                                                                         
while(ord($key = ReadKey(0)) != '13' )                                                                                                                                                                            
# This will continue until the Enter key is pressed (decimal value of 10)                                                                                                                                      
{                                                                                                                                                                                                              
    # For all value of ord($key) see http://www.asciitable.com/                                                                                                                                                
    if(ord($key) == 127 || ord($key) == 8 && (length($password) > 0)) {                                                                                                                                                                   
        # DEL/Backspace was pressed                                                                                                                                                                            
        #1. Remove the last char from the password                                                                                                                                                             
        chop($password);                                                                                                                                                                                       
        #2 move the cursor back by one, print a blank character, move the cursor back by one                                                                                                                   
        print "\b \b";                                                                                                                                                                                         
    } elsif(ord($key) > 32) {                                                                                                                                                                                  
        $password = $password.$key;                                                                                                                                                                            
        print "*";                                                                                                                                                                              
    }                                                                                                                                                                                                         
}                                                                                                                                                                                                              
ReadMode(0); #Reset the terminal once we are done
person Muhammad Hamayoon    schedule 07.02.2019

Вы пытались сохранить строку (чтобы ваша программа все еще могла ее прочитать) и узнать ее длину, а затем создать строку той же длины, но использовать только «*»?

person The Sheek Geek    schedule 31.03.2009
comment
Замена символа на * при вводе. - person Matthew Farwell; 31.03.2009