Wednesday, December 21, 2005

Switching off terminal echo in Perl

A delegate recently asked me how to switch echo off for password prompting. I couldn't remember, I thought it was Term::ReadLine. Actually it is Term::ReadKey - as expected the Perl Cookbook reminded me. Term::ReadKey is not a base module, but is present on ActiveState and Fedora installations, and easily installed from CPAN. Here is a simple script that works on both Linux and Windows (despite what the documentation says) :

use Term::ReadKey;

print 'Password: ';
ReadMode 'noecho';
my $password = ReadLine; # Corrected
ReadMode 'normal';
chomp $password;

print "Password was: $password\n";

Another delegate said something like "I guess another module will replace characters typed with asterisks". Well, that is not so simple. After some experimentation I came up with the following script, which has to use raw terminal input and take iinto account differences between Windows and Unix/Linux:

use Term::ReadKey;
use strict;

local $| = 1;
print 'Password: ';

my $password = '';
my $retn = $^O eq 'MSWin32'?"\r":"\n";

ReadMode 'raw';

while (1)
my $key;
# Loop waiting for a key to be pressed
while (!defined $key)
$key = ReadKey -1;

last if $key eq $retn;
$password .= $key;

print '*';

ReadMode 'normal';
print "\n";

print "Password was: $password\n";

Check the Term::ReadKey documentation for the arguments. Note that I have to wait for a key to be pressed this time, and write an unbuffered '*' (local $| = 1 makes STDOUT unbuffered).


Oliver vBK said...

-my $password = ReadLine,
+my $password = ReadLine;

Clive said...

Thanks, the error was there for four years before anyone noticed. I have corrected it.