For Programmers: Free Programming Magazines  


Home > Archive > PERL Miscellaneous > February 2005 > Read from keyboard









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Read from keyboard
* Tong *

2005-02-23, 3:59 pm

Hi,

Is there any way to read from keyboard/tty instead of STDIN?

My script process STDIN, while some time it need user interaction through
the keyboard, leaving the STDIN intact.

I've tried the getc(), and Term::ReadKey. However, they all seems to read
from STDIN. Please help.

Thanks

--
Tong (remove underscore(s) to reply)
*niX Power Tools Project: http://xpt.sourceforge.net/
- All free contribution & collection
jl_post@hotmail.com

2005-02-23, 3:59 pm

* Tong * wrote:
>
> Is there any way to read from keyboard/tty instead of STDIN?
>
> My script process STDIN, while some time it need user interaction

through
> the keyboard, leaving the STDIN intact.
>
> I've tried the getc(), and Term::ReadKey. However, they all seems to

read
> from STDIN. Please help.



Dear Tong,

This may not be the answer you're looking for, but did you try
reading all of STDIN first BEFORE requiring user interaction?

For example, if you wanted to ask a user his/her name, you might try
something like this:

my @allLinesFromSTDIN = <>;
print "What is your name? ";
my $name = <STDIN>; # don't forget to chomp() !

The first line reads all immediate lines from STDIN into an array,
leaving all subsequent reads from STDIN free to read from user input.
You are then free to process all the immediate STDIN lines later with
code like:

foreach (@allLinesFromSTDIN) # instead of "foreach(<> )"
{
# The $_ holds a line of input.
# Process $_ here...
}

I hope this helps, Tong.

-- Jean-Luc

Chris Mattern

2005-02-23, 3:59 pm

* Tong * wrote:

> Hi,
>
> Is there any way to read from keyboard/tty instead of STDIN?


Open /dev/tty and read from it.
>
> My script process STDIN, while some time it need user interaction through
> the keyboard, leaving the STDIN intact.
>
> I've tried the getc(), and Term::ReadKey. However, they all seems to read
> from STDIN. Please help.
>
> Thanks
>


--
Christopher Mattern

"Which one you figure tracked us?"
"The ugly one, sir."
"...Could you be more specific?"
Josef Moellers

2005-02-24, 8:57 am

jl_post@hotmail.com wrote:
> * Tong * wrote:
>=20
>=20
> through
>=20
>=20
> read
>=20
>=20
>=20
>=20
> Dear Tong,
>=20
> This may not be the answer you're looking for, but did you try
> reading all of STDIN first BEFORE requiring user interaction?
>=20
> For example, if you wanted to ask a user his/her name, you might try
> something like this:
>=20
> my @allLinesFromSTDIN =3D <>;
> print "What is your name? ";
> my $name =3D <STDIN>; # don't forget to chomp() !
>=20
> The first line reads all immediate lines from STDIN into an array,
> leaving all subsequent reads from STDIN free to read from user input.
> You are then free to process all the immediate STDIN lines later with
> code like:
>=20
> foreach (@allLinesFromSTDIN) # instead of "foreach(<> )"
> {
> # The $_ holds a line of input.
> # Process $_ here...
> }
>=20
> I hope this helps, Tong.


No, it won't. You did try your solution? What happened?
I tried, and it didn't work.

When you have read all of STDIN, any subsequent read will return EOF.=20
There is no magic that re-opens any terminal the process might (or might =

not) be connected to.
Imagine what happens if you run a program in the background which has=20
STDIN redirected to a file and which reads until EOF is detected and=20
then more! According to your logic, it will start to read from the=20
keyboard, completely confusing everything.

The direct solution to Tong's question is operating system dependent.=20
Unter Unix/Linux, Chris' suggestion of (re-) opening "/dev/tty" is=20
obviously a valid solution (afair, this is how programs like "cpio" work =

when requiring user interaction). Under another OS, (re-) opening "CON:" =

might work.
IMHO a much better solution is to avoid redirection of STDIN and require =

the input file to be passed as an argument. It should even work with the =

often used '-' as a command-line argument, as this (re-) opens STDIN,=20
which is what you want in that case, however, making the mixed=20
file-/user-input impossible.

Josef
--=20
Josef M=F6llers (Pinguinpfleger bei FSC)
If failure had no penalty success would not be a prize
-- T. Pratchett

Martin Kissner

2005-02-24, 8:57 pm

Josef Moellers wrote :

> IMHO a much better solution is to avoid redirection of STDIN and require
> the input file to be passed as an argument.


I thought about this solution, too.
But if STDIN is reading from a pipe this will not be possible AFAIK.
If there is a way to handle this, I would be interested in how.

Best Regards
Martin

--
perl -e '$|=1;&p(7.74.117.115.116.32);&s();&p(97.110.111);&p(116.104.101
..114);&s;&p(32.112.101.114.108);&s();&p(32.104.97.99.107.101.114.10);sub
s{sleep 1};sub p(){print "@_"}'
jl_post@hotmail.com

2005-02-25, 3:58 am

> jl_post@hotmail.com wrote:
input.

Josef Moellers replied:[color=darkred]
>
> No, it won't. You did try your solution? What happened?
> I tried, and it didn't work.


Hmmm... it appears you're right. I just tried it with feeding input
from a pipe, and it didn't work, just as you said.

I did have a solution, however. But instead of piping the input in
I specified the file (with the input) as a parameter to be read in with
Perl's diamond operator ("<>"). Since the diamond operator can be used
to read STDIN and to open files specified at the command line, I always
thought they were functionally interchangeable. But as you explained,
if the diamond operator is used to read STDIN, any subsequent read of
STDIN will return EOF.

The reason I tested it by reading the input from a file (instead of
from a pipe) was because I've sometimes had problems with Perl running
under Win32 reading from a pipe (but more on that later in this
post...).

> The direct solution to Tong's question is operating system
> dependent. Unter Unix/Linux, Chris' suggestion of
> (re-) opening "/dev/tty" is obviously a valid solution (afair,
> this is how programs like "cpio" work when requiring user
> interaction). Under another OS, (re-) opening "CON:"
> might work.


For the record, I tested Win32 ActiveState Perl with both "CON" and
"CON:" and they both seem to work.

> IMHO a much better solution is to avoid redirection of STDIN and
> require the input file to be passed as an argument.


I agree with you there, as that's what I used to test my sample
data... :)

As I mentioned earlier, I found a problem reading piped input on
Win32. You can reproduce this problem by creating a short, one-line
file named "cat.pl" that consists of the line:

print <>;

Then type, at the Win32-DOS prompt:

cat.pl < cat.pl

You'd think it would print out its contents, right? Instead, I get
nothing (I see the DOS prompt right away).

Today I figured out that I can "fix" this problem by explicitly
calling the Perl interpreter, like this:

perl cat.pl < cat.pl

This works as it should.

So here's a question: Why does omitting "perl" prevent the input
from being read in correctly? I'm sure this is a Win32-DOS-MS issue
and not a Perl bug, but I'm not absolutely certain.

Whatever is causing this, this behavoir is the reason I avoided
testing my original solution with actual piped input (as it seemed
unpredictable at the time), and instead opted to test with the file
specified at the command line, thinking that it would make no
difference. I was wrong, of course, about it making no difference.

(For those interested, my "perl -v" output is:

This is perl, v5.8.0 built for MSWin32-x86-multi-thread
(with 1 registered patch, see perl -V for more detail)
Copyright 1987-2002, Larry Wall
Binary build 805 provided by ActiveState Corp.
http://www.ActiveState.com
Built 18:08:02 Feb 4 2003
)

Anyway, Josef, thanks for pointing out my error.

-- Jean-Luc

GreenLeaf

2005-02-25, 3:58 am

jl_post@hotmail.com wrote:

> As I mentioned earlier, I found a problem reading piped input on
> Win32. You can reproduce this problem by creating a short, one-line
> file named "cat.pl" that consists of the line:
>
> print <>;
>
> Then type, at the Win32-DOS prompt:
>
> cat.pl < cat.pl
>
> You'd think it would print out its contents, right? Instead, I get
> nothing (I see the DOS prompt right away).


Why should one expect so? If .pl extension is not associated with perl
but with, say, your editor, it's supposed to open cat.pl in your editor.
If it's associated with perl, the following is applicable:

Correct me if I'm wrong, I don't know much on _exactly_ how '<' is
supposed to work in Unix, but I guess this is not a 'pipe' in Windows.
They officially acknowledge the word pipe only for '|'.

<quote:ms>

> : Reads the command input from a file, instead of reading input

from the keyboard.

| : Reads the output from one command and writes it to the input of
another command. *Also known as a pipe*.

http://www.microsoft.com/resources/...edirection.mspx
</quote:ms>

See, their redirection operator is supposed to read from _files_. When
_MS_ says _file_, it's not always safe to assume that it would work for
other devices, IMHO. Sometimes they work similarly, as for the case of
CON.

>
> Today I figured out that I can "fix" this problem by explicitly
> calling the Perl interpreter, like this:
>
> perl cat.pl < cat.pl
>
> This works as it should.



Just for the record, so does

perl cat.pl | perl cat.pl

but not

perl cat.pl < perl cat.pl

for obvious reasons :-)

<output>
------------------------------------------
C:\temp>perl cat.pl |perl cat.pl
this
is
a
test
^Z (typed EOF here)
this
is
a
test
C:\temp>
-------------------------------------------
C:\temp>perl cat.pl < perl cat.pl
The system cannot find the file specified.
</output>

This is because it's looking for a _file_ named perl. Well, in *my*
case, Linux produced exactly the same behavior.

<output>
[greenleaf@lah greenleaf]$ echo 'print <>' > cat.pl
[greenleaf@lah greenleaf]$ perl cat.pl | perl cat.pl
this
is a
test. (typed EOF here)
this
is a
test.
[greenleaf@lah greenleaf]$ perl cat.pl < perl cat.pl
bash: perl: No such file or directory
</output>


> So here's a question: Why does omitting "perl" prevent the input
> from being read in correctly?


I think this is answered above. 'Opening' a non-executable in windows
means opening in it the designated application. Just curious: what's
your default association for file type .pl? If it's the editor and if
you had already opened the file, it may be the case that you did not
notice it.

> I'm sure this is a Win32-DOS-MS issue
> and not a Perl bug, but I'm not absolutely certain.


Exactly.

> (For those interested, my "perl -v" output is:


Apparently your perl is well alive and kicking ;-). The issue (not
a problem anymore I guess) is clearly about redirection. :)

HTH,
sat.

jl_post@hotmail.com

2005-02-25, 3:59 pm

> jl_post@hotmail.com wrote:
input[color=darkred]

GreenLeaf replied:[color=darkred]
>
> I think this is answered above. 'Opening' a non-executable in windows
> means opening in it the designated application. Just curious: what's
> your default association for file type .pl? If it's the editor and if


> you had already opened the file, it may be the case that you did not
> notice it.



My default association for file type .pl is perl (specifically,
D:\Perl\bin\perl.exe). The script I showed you definitely runs. It's
hard to tell as that one-line script, so let me propose this slightly
longer script, named "cat.pl":


# Code:
print "Running $0 ...\n";
print <>;


Now, when I type:

cat.pl cat.pl

at the prompt I get the expected output:

Running path\cat.pl ...
# Code:
print "Running $0 ...\n";
print <>;

But when I type:

cat.pl < cat.pl

I just get:

Running path\cat.pl ...

and when I type this (using DOS "type" which is like Unix "cat"):

type cat.pl | cat.pl

I get the output:

Running path\cat.pl ...
The process tried to write to a nonexistent pipe.

I'm clueless as to why I get the error message of a nonexistent pipe.

When I place "perl" in front of cat.pl, like this:

perl cat.pl < cat.pl

or:

type cat.pl | perl cat.pl

I get the expected output of:

Running cat.pl ...
# Code:
print "Running $0 ...\n";
print <>;

Obviously, even without "perl" at the command line the Perl script
is still running (otherwise it wouldn't print "Running ..."), but it
seems to have problems reading in standard input when read from a pipe
or from re-direction. Of course, this problem only happens under
Win32-DOS (Unix flavors don't seem to have this problem).

This is an odd problem that can be easily "fixed" by placing "perl"
in front of the script to be executed, so it's not a huge show-stopper
problem. But still, it's nice to know about it in case it ever comes
up.

If anyone knows why this happens (that is, omitting "perl" under a
Win32-DOS command-line causes a script to have problems reading STDIN
from a pipe), feel free to let me know.

-- Jean-Luc

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com