2009-03-31 6 views
18

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

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

ответ

15

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

#!/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"; 
+3

Это не работает под Windows. Он отлично работает, пока вы не нажмете клавишу ввода, когда вам нужно нажать четыре раза, чтобы он реагировал. Если вы используете ReadMode (2), то он работает нормально, но не эхо, пока вы не нажмете return. Не отображать * может быть приемлемой альтернативой –

+2

Это не работает в Windows, потому что десятичное значение ascii ключа Enter или Return равно 13 (CR: возврат каретки). Как только вы замените строку while (ord ($ key = ReadKey (0))! = 10) с while (ord ($ key = ReadKey (0))! = 13), он работает лучше :) – Damien

+0

Возможно, вам также захочется проверить «\ x03» (^ C); Кроме того, вы, вероятно, захотите испустить «\ b \ b» только в том случае, если длина ($ пароль)> 0 или на основе возвращаемого значения chop() (чтобы избежать стирания приглашения, если пользователь продолжает возвращать назад) – vladr

-5

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

+0

Замена символа * при вводе текста. –

7

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

25

В прошлом я использовал IO::Prompt для этого.

use IO::Prompt; 
my $password = prompt('Password:', -e => '*'); 
print "$password\n"; 
+3

* [STATUS ] (http://search.cpan.org/dist/IO-Prompt/lib/IO/Prompt.pm#STATUS): этот модуль больше не поддерживается. Вместо этого используйте модуль IO :: Prompter. * – reinierpost

17

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

system('stty','-echo'); 
chop($password=<STDIN>); 
system('stty','echo'); 
+0

'chomp' будет лучше, чем' chop' –

1

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

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; 
} 
+0

Нет необходимости в $ count, length ($ password). – vladr