Perl One Liner: Pick


Abstract

This document is the first one of a series in which I want to present and explain some of the Perl one liners that I wrote for fun or profit during the years. I hope that you will enjoy.

Introduction

One of my favourite books is The Unix Programming Environment by Brian W. Kernighan and Rob Pike.

The book is full of examples of both Shell and C programming. Some of the examples are first written using the Shell and then, after describing the limitations of such approach, the authors provide the same example in C.

One of the examples in the book is a little application, but indeed very useful, called "pick".

Pick

Pick is a very simple application. The only thing it does is reading from STDIN and, for each line, asking the user if the line should be printed out on STDOUT. The application can be used to make some command a little bit more interactive.

For instance, consider an application that produces a list of files and for each of them it asks the user if the file needs to be moved or cancelled.

The book presents pick in the two usual flavours: Shell and C. I started immediately to think "this is the kind of application that I would have written in Perl". Why? Just for fun really; I would not even write that in a ".pl" file but I would have preferred writing that as a one liner application and maybe refering to that as an aliased command in bash (or zsh).

Our Implementation

The implementation is not as straightforward as it could looks like at the very first moment. First of all, the application needs to both read the STDIN for the input lines to be shown to the user and to read the choice of the user (output the line or not). Second, but less dramatic, being able to both output the request of the line and the line itself.

Let's start from the second one because it is trivial. The question to the user can be printed on STDERR and the output lines, by definition, on STDOUT.

Now, let's face the first problem. How is that possible to both read the input and the user's choice fron STDIN? That's actually easier that you can think. Since the application needs to be run inside a terminal, is will for sure have a TTY attached to that.

I expect you to ask something like "so what?". Well, that's exactly the point: the STDIN is just an abstraction over the input of a program. That's the reason why we can redirect to the STDIN of a program a file or the output of another program. If there is no redirection, the terminal takes care of redirecting the terminal stream to the STDIN of the program. Since a file can open for reading more than one file and in UNIX (almost) everything is a file, we just need to explicitly open the TTY as a file and read from that what the user is typing.

A UNIX system can have many different TTYs, so, "what's mine?". UNIX helps in this case as well. On one side it is true that there are many TTYs but it also true that the terminal in which an application is running can refer to its own TTY with the default name /dev/tty.

Let's proceed with the implementation:

nids@crimson: ~/Test/Pick$ cat test.txt
aaa
bbb
ccc
ddd
eee
fff
nids@crimson: ~/Test/Pick$ perl -nle 'BEGIN {open $tty, "<", "/dev/tty"; } print STDERR "$_ ?"; $r = <$tty>; print if($r =~ /^y$/i)' < test.txt > test.out
aaa ?
y
bbb ?
y
ccc ?
n
ddd ?
n
eee ?
y
fff ?
n
nids@crimson: ~/Test/Pick$ cat test.out 
aaa
bbb
eee
nids@crimson: ~/Test/Pick$

It works!!!! I cannot believe it!!!!

Of course, this little program lacks all the banal safety and consistency checks on streams and on the user's input but it is a good starting point to make something a little bit more robust, flexible and maybe nicer (what about colors?).

Conclusions

In this document we saw a nice trick to simulate two different STDIN streams for our application and that worked well and it was useful to know.

But the must important thing is that we had a lot of fun!

Post Scrictum

The one liner was tested on a Linux box using perl 5.10 but you are more than welcome to try it out on any UNIX flavour of your choice and send me your fixes and comments at the address reported at the very bottom of this page.