[comp.lang.perl] STDIN waits for ^D, not newline

halbert@halbert.crl.dec.com (Dan Halbert) (05/09/90)

(Using Perl version:
$Header: perly.c, v 3.0.1.4 90/02/28 18:06:41 lwall Locked $
Patch level: 15)

I'm writing an interactive terminal program in perl. It prompts the user
and reads from STDIN.

If you try this program:

print "prompt: ";
$a = <STDIN>;
print $a;

then a carriage return will end the input. (That is, <STDIN> will read
one line.)

However, if you try:

print "prompt: ";
local ($a) = <STDIN>;
print $a;

then STDIN keeps reading input until I type ^D.

In my program, the local() is in a subroutine, of course, but that isn't
necessary to reproduce the problem.

Opening "-" explicitly doesn't solve the problem.

I just started looking at comp.lang.perl; sorry if this is old hat.

--Dan Halbert

tneff@bfmny0.UU.NET (Tom Neff) (05/09/90)

In article <5249@crltrx.crl.dec.com> halbert@crl.dec.com writes:
>print "prompt: ";
>$a = <STDIN>;
>print $a;
>
>then a carriage return will end the input. (That is, <STDIN> will read
>one line.)

>print "prompt: ";
>local ($a) = <STDIN>;
>print $a;
>
>then STDIN keeps reading input until I type ^D.


The local() construction is treated as an array.  As the manual states,
$var=<FILE> reads one line but @array=<FILE> reads the whole thing.


The workaround is to say

	print "prompt: ";
	local ($a);
	$a = <STDIN>;
	print $a;

-- 
"NASA Awards Acronym Generation       :(%( :  Tom Neff
System (AGS) Contract For Space       : )%):  tneff%bfmny@UUNET.UU.NET
Station Freedom" - release 1989-9891  :(%( :  ...!uunet!bfmny0!tneff

merlyn@iwarp.intel.com (Randal Schwartz) (05/10/90)

In article <5249@crltrx.crl.dec.com>, halbert@halbert (Dan Halbert) writes:
| (Using Perl version:
| $Header: perly.c, v 3.0.1.4 90/02/28 18:06:41 lwall Locked $
| Patch level: 15)
| 
| I'm writing an interactive terminal program in perl. It prompts the user
| and reads from STDIN.
| 
| If you try this program:
| 
| print "prompt: ";
| $a = <STDIN>;
| print $a;
| 
| then a carriage return will end the input. (That is, <STDIN> will read
| one line.)
| 
| However, if you try:
| 
| print "prompt: ";
| local ($a) = <STDIN>;
| print $a;
| 
| then STDIN keeps reading input until I type ^D.
| 
| In my program, the local() is in a subroutine, of course, but that isn't
| necessary to reproduce the problem.
| 
| Opening "-" explicitly doesn't solve the problem.
| 
| I just started looking at comp.lang.perl; sorry if this is old hat.

Not old hat.  I don't recall seeing this one before.

But, the problem (without testing it) is that
	local($a) = <STDIN>;
is an _array assignment_.  So, <STDIN>, being very helpful, is sucking
all of standard input into an array, and then giving the first line
into $a, while discarding the rest.
This works better (but looks ugly -- Larry?):

	local($a) = "".<STDIN>;

Which basically says to interpret <STDIN> in a scalar context (a
string concatenation), and pass the result to the assignment.

$|=1;$_=",rekcah lreP rehtona tsuJ";while(length){exit wait if fork;s/.$//;print$&;}
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (05/10/90)

In article <5249@crltrx.crl.dec.com> halbert@crl.dec.com writes:
: However, if you try:
: 
: print "prompt: ";
: local ($a) = <STDIN>;
: print $a;
: 
: then STDIN keeps reading input until I type ^D.
: 
: In my program, the local() is in a subroutine, of course, but that isn't
: necessary to reproduce the problem.

This is because local is really just a modifier on a list lvalue, so
you're really doing the same as the following:

	local($a);
	($a) = <STDIN>;

Since ($a) is a list, the <STDIN> is being evaluated in an array context,
and returning the entire file.

You could force a scalar context by concatenating a null string, but it's
probably more efficient to separate it out thusly:

	local($a);
	$a = <STDIN>;

Larry