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

I want to read in a stream of characters from STDIN, ten process the information, then ask the user questions and read their answer.

Problem is, I can't figure out what I need to do to seperate the two stages.

Code:

#!/usr/bin/perl # # A program that accepts input from the cmputil command and will diff +the files # in question, prompting the user for a decision, and build an action +file # use File::Basename; $| = 1; open IN, "<$ARGV[0]"; open OUT, ">differences"; while (<IN>) { chop $_; ($file,$problem,@machines) = split(/,/, $_); ($name,$path,$suffix) = fileparse($file,""); print "$name -- $path -- $suffix\n"; if($problem eq "different") { # get the file from the remote machine foreach $machine (@machines) { next if ($machine eq ""); $tempfile = "/tmp/" . $name . "_" . $machine; `rcp $machine:$file $tempfile`; print "comparing $name from $machine\n"; system "diff $file $tempfile"; print "(k)eep or (i)gnore this difference?\n"; $resp = <>; print ">>$resp<<\n"; if($resp eq "k") { print OUT "$machine $file\n"; } } } }

The problem I have is the line $resp = <>; returns immediately without waiting for the user to input anything.

Do I need to flush STDIN or something?

---
I hate my sig

edited: Thu Nov 27 18:44:17 2003 by jeffa - s/pre/code/g

Replies are listed 'Best First'.
Re: Reading from STDIN
by holo (Monk) on Nov 27, 2003 at 19:20 UTC

    I know you didn't ask, but some of the code used here is not very secure. Other parts can be written better (if you plan to make the script portable)

    Here is an updated version:

    #!/usr/bin/perl use strict; # amen use warnings 'all'; # or use perl -w use File::Basename; $| = 1; # :raw for brain-dead OSes (or use binmode). open my $in, '<:raw', $ARGV[0]; # use $in not IN open my $out, '>:raw', "differences"; while (<$in>) { chomp; ($file,$problem,@machines) = split(/,/, $_); ($name,$path,$suffix) = fileparse($file,""); print "$name -- $path -- $suffix\n"; if($problem eq "different") { # get the file from the remote machine foreach $machine (@machines) { next if ($machine eq ""); # consider using File::Temp here $tempfile = "/tmp/" . $name . "_" . $machine; # should consider using File::Remote here system("rcp", "$machine:$file", $tempfile) == 0 or die "Execution (rcp) failed: $?"; # why not use Text::Diff ? print "comparing $name from $machine\n"; system("diff", $file, $tempfile) == 0 or die "Execution (diff) failed: $?"; print "(k)eep or (i)gnore this difference?\n"; $resp = <STDIN>; print ">>$resp<<\n"; if($resp eq "k") { print $out "$machine $file\n"; } } } }

    Executing stuff is always insecure. You should either consider using taint mode (-T) or use Perl modules to perform the same task in most cases (in all cases in the example above)

    Documents for these modules are here: File::Remote, File::Temp and Text::Diff. They are more or less simple to use, a lot safer and sometimes faster. (since they don't fork() and exec())

    Update: Use chomp instead of chop.

      I've been meaning to reply to this for a while. Most of the perl I write has to be backwards compatible to early 4.0 era versions of perl. Also, the code needs to be able to run on every unix platform we support. So its just not feasible to use CPAN modules for everything, becasue garanteed, it'll break somewhere. Coincidentaly, thats why I also have to write in pure sh shell....

      I hate my sig
Re: Reading from STDIN
by holo (Monk) on Nov 27, 2003 at 18:39 UTC

    $resp = <>; is reading the next line in the next file in @ARGV, not from STDIN. You probably mean $resp = <STDIN>; there.

    See "I/O Operators" in perlop to see exactly what <> is doing.

      To clarify holo's response, <> will read from STDIN only when all the files on the commandline have been exausted. In scripts without arguments, this will always read from STDIN. But since your script takes arguments, it won't DWIM (at least, not right away...)


      Who is Kayser Söze?

        <> will not read from STDIN if there are arguments; not even when it runs out of files. Proof:

        $ echo "one" > file1; echo "two" > file2 $ echo "three" | perl -e 'print while <>' file1 file2 one two

        This script requires at least one argument to work so I assume that unless @ARGV is cleared, <> will never read from STDIN.