Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

the greedy diamond, or leggo my STDIN

by headybrew (Beadle)
on Jul 03, 2007 at 19:04 UTC ( [id://624753]=perlquestion: print w/replies, xml ) Need Help??

headybrew has asked for the wisdom of the Perl Monks concerning the following question:

ok, my monkitudionous friends...

Why doesn't this work?

$ ls | sillytest

where sillytest is the following perl script:

#!/usr/bin/perl my @msg = (<>); chomp(@msg); print join("\n",@msg); print "What do you want to do with this message?"; my $response = <STDIN>; print $response;
It receives and prints the @msg lines properly, but then how do I get it to get input from the keyboard again after I'm done reading from the diamond operator?

Oh, I'm sure this is an easy one... my apologies for boring you with mundanities.

Replies are listed 'Best First'.
Re: the greedy diamond, or leggo my STDIN
by Joost (Canon) on Jul 03, 2007 at 19:40 UTC
      Ah hah! I just did this.

      close(STDIN); open(STDIN,"<","/dev/tty") or die "Can't reopen STDIN from /dev/tty: $ +!";

      I don't know if it's any better or worse than using a new filehandle, but it keeps me happy.

      BTW: What would I do on a non-posix system?

        I don't know if it's any better or worse than using a new filehandle, but it keeps me happy.

        It's exactly as the same IMHO and in both ways it keeps me unhappy: I find your way to do what you want to do clumsy and error prone, which is probably the reason why I couldn't understand your question at all, first.

        BTW: What would I do on a non-posix system?

        But seriously, why don't you use <>'s magic instead?

        q:~/tmp [22:37:14]$ cat headybrew.pl #!/usr/bin/perl chomp(my @msg =<>); print @msg, "\n"; print "What do you want to do with this message?"; $response = <STDIN>; print $response; q:~/tmp [22:37:17]$ ./headybrew.pl 'ls|' headybrew.plheadybrew.pl~ What do you want to do with this message?foo foo
      Thanks.

      Sounds like that would work, but isn't there a way to just switch my STDIN back to the keyboard?

        Sounds like that would work, but isn't there a way to just switch my STDIN back to the keyboard?

        Nope, because it's not been switched forth. It has been switched away once and for all out of your program. Of course you can reopen STDIN to whatever you want, if you like:

        q:~/tmp [22:27:50]$ cat headybrew.pl #!/usr/bin/perl chomp(my @msg =<>); print @msg, "\n"; print "What do you want to do with this message?"; close STDIN; open STDIN, '<', '/dev/tty' or die "Can't read from /dev/tty: $!\n"; my $response = <STDIN>; print $response; q:~/tmp [22:27:58]$ ls | ./headybrew.pl headybrew.plheadybrew.pl~ What do you want to do with this message?foo foo q:~/tmp [22:28:08]$

        But then you rely on something hardcoded that you know or want to be the keyboard. Because from within your program you have no notion of "what" the keyboard would have been, had STDIN not been redirected by the shell.

Re: the greedy diamond, or leggo my STDIN
by ikegami (Patriarch) on Jul 03, 2007 at 21:24 UTC
    If you want to provide arguments to a program that needs the interact with the user, why not use parameters?
    #!/usr/bin/perl die("usage: sillytest file [file [file [...]]]\n") if not @ARGV; my @msg = <>; chomp(@msg); print(join("\n", @msg)); print "What do you want to do with this message?"; my $response = <STDIN>; print $response;

    To pass the output of ls, you'd do
    sillytest `ls`
    or just
    sillytest *

    By the way, you might be interested in
    my $msg = do { local $/; <> }; print($msg);

Re: the greedy diamond, or leggo my STDIN
by doom (Deacon) on Jul 03, 2007 at 20:59 UTC
    I'm a little suprised no one has pointed you at Term::ReadLine yet (in the standard library).

    Term::UI (on CPAN) looks okay, too.

Re: the greedy diamond, or leggo my STDIN
by blazar (Canon) on Jul 03, 2007 at 19:41 UTC
    It receives and prints the @msg lines properly, but then how do I get it to get input from the keyboard again after I'm done reading from the diamond operator?

    You just get it:

    Windows:

    C:\temp>headybrew.pl foo bar baz ^Z foo bar bazWhat do you want to do with this message?wtf wtf

    *NIX:

    wolfgang:~ [21:40:12]$ ./headybrew.pl foo bar baz foo bar bazWhat do you want to do with this message?wtf wtf

    You just have to pass an end of file to interrupt the first sequence, which happens to be ^Z in the former environment and ^D in the latter. Or did you mean anything else?

    Update: apologies, hadn't noticed the $ ls | sillytest, my fault, but perhaps you may have put that in <code> tags too, for maximum visibility.

      Yeah, but I can't pass and EOF or anything else in. I'm at the mercy of what get's passed in from some other program's output.
Re: the greedy diamond, or leggo my STDIN
by DrHyde (Prior) on Jul 04, 2007 at 09:22 UTC

    It does work. It just doesn't do what you expect because you don't understand filehandles properly :-)

    STDIN is just another filehandle. Normally it is opened to whatever device is attached to your console. But because you are piping another program's output into your program's input, your program's STDIN is instead attached to the other program's STDOUT. It will remain attached to that until you tell it otherwise.

    You might find this tutorial useful, in particular the few pages starting here.

Re: the greedy diamond, or leggo my STDIN
by Moron (Curate) on Jul 04, 2007 at 08:46 UTC
    or transfer the stream to arguments...
    $ ls | xargs sillytest
    #!/usr/bin/perl my @msg = join "\n", @ARGV; # continue normally - STDIN was not redirected by xargs
    update: and if on a non-*nix platform, you can roll your own xargs easily enough:
    #!/usr/bin/perl # XARGS.EXE v0.1 shift @ARGV; push @ARGV, <STDIN>; chomp @ARGV; exec join( ' '. @ARGV;
    __________________________________________________________________________________

    ^M Free your mind!

Re: the greedy diamond, or leggo my STDIN
by mattr (Curate) on Jul 07, 2007 at 13:37 UTC
    reap this pls.
Re: the greedy diamond, or leggo my STDIN
by kart124 (Initiate) on Jul 04, 2007 at 12:44 UTC
    Hey I dont know the complexity or what you wish to do further. But here is a very simple suggestion:

    use the sleep <int> function instead.

    #!/usr/bin/perl my @msg = (<>); chomp(@msg); print join("\n",@msg),"\n"; print STDOUT "What do you want to do with this message?\n";$|++; sleep (5); my $response = <STDIN>; print $response;$|++;
      All that does is cause the program to wait 5 seconds before exiting. It still doesn't receive any input from the keyboard (because, as others have pointed out above, STDIN isn't connected to the keyboard).

      And <code> tags are your friends.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://624753]
Approved by kyle
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-04-19 02:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found