How can I read a single character from a file? From the keyboard?

You can use the builtin getc() function for most filehandles, but it won't (easily) work on a terminal device. For STDIN, either use the Term::ReadKey module from CPAN or use the sample code in perlfunc/getc.

If your system supports the portable operating system programming interface (POSIX), you can use the following code, which you'll note turns off echo processing as well.

    #!/usr/bin/perl -w
    use strict;
    $| = 1;
    for (1..4) {
	my $got;
	print "gimme: ";
	$got = getone();
	print "--> $got\n";
    }
    exit;
    BEGIN {
	use POSIX qw(:termios_h);
	my ($term, $oterm, $echo, $noecho, $fd_stdin);
	$fd_stdin = fileno(STDIN);
	$term     = POSIX::Termios->new();
	$term->getattr($fd_stdin);
	$oterm     = $term->getlflag();
	$echo     = ECHO | ECHOK | ICANON;
	$noecho   = $oterm & ~$echo;
	sub cbreak {
	    $term->setlflag($noecho);
	    $term->setcc(VTIME, 1);
	    $term->setattr($fd_stdin, TCSANOW);
	}
	sub cooked {
	    $term->setlflag($oterm);
	    $term->setcc(VTIME, 0);
	    $term->setattr($fd_stdin, TCSANOW);
	}
	sub getone {
	    my $key = '';
	    cbreak();
	    sysread(STDIN, $key, 1);
	    cooked();
	    return $key;
	}
    }
    END { cooked() }
The Term::ReadKey module from CPAN may be easier to use. Recent versions include also support for non-portable systems as well.

    use Term::ReadKey;
    open(TTY, "</dev/tty");
    print "Gimme a char: ";
    ReadMode "raw";
    $key = ReadKey 0, *TTY;
    ReadMode "normal";
    printf "\nYou said %s, char number %03d\n",
        $key, ord $key;

Back to perlfaq5