No Solution without a Problem

jonasbn on 2007-02-10T15:42:51

Our local LUG, (SSLUG) have a general programming list. A part from other languages, a Perl question gets posted once in a while.

Today some guy asked a question about reading two different things via STDIN, like this:

./test.pl < fil1


After reading the file the program should ask questions to the user, recording the responses from STDIN.

The example outline was pretty simple:

#! /usr/bin/perl

use strict; use warnings;

my @lines; my $line; while ($line = ) { push @lines,$line; } #STDIN->clearerr; #seek(STDIN, 0, 1);

my $input; foreach $line (@lines) { print "$line"; $input = ; print "You said $input\n"; }


But the author of the question had problems getting the responses from STDIN.

I had no idea how to solve this, probably because I would never implement a program this way - but I found the problem quite interesting. So I read a few man pages, tried out a few things, but without luck - I was simply not familiar with that part of the Perl language.

I primarily do web and database stuff, I hardly ever work on files and if I do it is very basic operations and I love using Tie::Array.

Before I found a solution, the author posted the solution himself.

I refactored his original to give a more suitable example:

A small program, which reads a number of questions from a file via STDIN, prompts the user for a response via STDIN and prints question and response in conjunction to STDERR.

#! /usr/bin/perl -w

use strict;

my @questions; while (my $question = ) { push @questions,$question; } close(STDIN);

open(STDIN,'/dev/tty'); foreach (@questions) { print "$_"; print STDERR "$_"; print STDERR ."\n"; }

exit(0);

__END__

Usage: questions.pl data.txt


What bothers me is the fact that I did not know how to do this is Perl, but as written earlier, I would never come across a problem like this and therefor not the solution.

I wish there would be an open variant of the Perl Cookbook, like a wiki, where these recipes/solutions providing basic solutions to basic problems using either CPAN modules or preferably basic Perl could be shared.

In order to improve as a programmer I guess is you have to be exposed to a variation of problems, but also a variation of tools, here meaning programming languages. I remember when going back from VB.NET and PL/SQL to Perl I saw Perl in a new light.

I also remember when I started out with 'Learning Perl', I loved solving the tasks, since this gave me exposure to Perl parts, without having being related to work or something else with a deadline, some legacy code or cultural dependency controlling the way you would or could solve the problem. Of course there is also a cultural influence imposed by the author and possibly the author of Perl and I could go on.

It is nice to sometimes to be able look at problem with a white sheet of paper and be able to start from scratch. Break the problem down, prototype, experiment, understand and finally implement and solve the problem.

The paradigme I attempt to enforce it an approach of divide and conquer, but unless exposed to diverse problems the solutions will most often be based on the same, sometimes bad solutions and not necessarily the best practice...

I guess the bare bone nature outlined by the poster to the LUG list made me interested there was a working snippet to a simple problem, but not a solution.

Well anyway I might have to consider how to get exposed to a larger variety of problems one way or the other, so I can learn a wider variety of solutions and a wider use of Perl and other tools.


Far too complicated

Aristotle on 2007-02-10T16:40:17

#!/usr/bin/perl -w
use strict;

die "Usage: $0 questions.txt [morequestions.txt ...] > answers.txt"
    if not @ARGV;

while( <> ) {
    print STDERR $_;
    print $_;
    print scalar <STDIN>;
}

The key is that the question files must be given as commandline arguments, not passed in via redirection. The <> diamond operator will read from the files listed in @ARGV and you can read STDIN separately from it at the same time.

Re:Far too complicated

jonasbn on 2007-02-10T17:01:02

Ah, much more in line with what I would probably do, however not as short and artistic.

Thanks for the solution it is very nice.

Re:Far too complicated

phaylon on 2007-02-11T16:51:08

Yea, this is a suitable solution for



foo.pl inputfile.txt



But what if you want to do



grep bar inputfile.txt | foo.pl



instead?

Re:Far too complicated

Aristotle on 2007-02-11T17:58:29

If you use bash, you can use process substitution instead:

foo.pl <( grep bar inputfile.txt )

Re:Far too complicated

phaylon on 2007-02-12T13:21:02

Far too complicated :)

Re:Far too complicated

Aristotle on 2007-02-12T15:35:17

It’s more reliable (/dev/tty isn’t always available) and more flexible (you don’t need Expect to feed it answers from a file, you just redirect standard input). But the clincher for me is that it’s still less and simpler code. Cf. Carter’s Compass.

Re:Far too complicated

phaylon on 2007-02-12T15:59:31

Well, that's a borderline. IMO the API should always be nicer than the guts :)