Search code examples
perlpipestdin

How to read password line after pipe input to Perl script


I'm trying to read STDIN and then get user input line without displaying it in terminal.

The Term::ReadKey's solution with ReadMode('noecho') will not work because it uses <STDIN> and if it is not empty it immediately takes(that what is supposed to be file, e.g. piped data) as input and not actually works:

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

my $_stdin = <STDIN>;
print "Enter your password:\n";
ReadMode('noecho');
my $_pass = ReadLine(0); # This one uses <STDIN>!
ReadMode(0);
print "STDIN:\n$_stdin\nPassword:\n$_pass\n";

output:

$ echo "some data" | perl term-readkey.pl
Enter your password:
Use of uninitialized value $_pass in concatenation (.) or string at term-readkey.pl line 10, <STDIN> line 1. 
STDIN:
some data

Password:

The only solution that I come with is to use Term::ReadLine which seems not using <STDIN> as Term::ReadKey, but the problem is that output of the $_term->readline() is visible:

use warnings;
use strict;
use Term::ReadLine;

my $_stdin = <STDIN>;
my $_term = Term::ReadLine->new('term');
my $_pass = $_term->readline("Enter your password:\n");
print "STDIN:\n$_stdin\nPassword:\n$_pass\n";

output:

$ echo "some data" | perl term-readkey.pl
Enter your password:
25 # actually entered it, and its visible...
STDIN:
some data

Password:
25

There was a similar question, but the answer is working only on Unix'y systems and input is visible...


Solution

  • So I've found solution, which was quite simple:

    Using the Term::ReadKey's ReadMode with Term::ReadLine's term's IN, example:

    use Term::ReadLine;
    use Term::ReadKey;
    
    my $_stdin = <STDIN>;
    my $_term = Term::ReadLine->new('term');
    ReadMode('noecho', $_term->IN);
    my $_pass = $_term->readline("Enter your password:\n");
    ReadMode(0, $_term->IN);
    print "STDIN:\n$_stdin\nPassword:\n$_pass\n";
    

    or(thanks to Ujin)

    use Term::ReadLine;
    use Term::ReadKey;
    
    my $_stdin = <STDIN>;
    my $term = Term::ReadLine->new('term');
    my @_IO = $term->findConsole();
    my $_IN = $_IO[0];
    print "INPUT is: $_IN\n";
    open TTY, '<', $_IN;
    print "Enter your password:\n";
    ReadMode('noecho', TTY);
    my $_pass = <TTY>;
    ReadMode(0, TTY);
    close TTY;
    print "STDIN:\n$_stdin\nPassword:\n$_pass\n";
    

    outputs:

    Enter your password:
         # here enter hiddenly
    STDIN:
    stdin input
    
    Password:
    paws