[Gllug] Re: Bizarre shell behaviour

Per Gregers Bilse bilse at networksignature.com
Sat Nov 8 12:40:29 UTC 2003


> From: Dylan <dylan at dylan.me.uk>
> Subject: Re: [Gllug] Bizarre shell behaviour
> 
> On Friday 07 November 2003 23:57 pm, Bruce Richardson wrote:
> > On Fri, Nov 07, 2003 at 11:27:51PM +0000, Dylan wrote:
> > > On Friday 07 November 2003 17:16 pm, Tethys wrote:
> > > > Take the following shell script. Run it:
> > > >
> > > > 	#!/bin/sh
> > > >
> > > > 	count=0
> > > > 	while read var
> > > > 	do
> > > > 		count=1
> > > > 	done < /etc/group
> > > >
> > > > 	echo $count
> > >
> > > Just out of interest (and 'cos I'm trying to learn shell scripting) can
> > > someone explain what this is supposed to achieve. The loop is obvious,
> > > but what's the redirection all about?
> >
> > It's reading from the file /etc/group, one line at a time.
> 
> Thanks. I added an echo $var before the done and got a listing of the file so 
> I figure each line is going into $var. How does this work then?

"man bash"; at some 80 pages, it makes for nice weekend reading.

To answer your question, keep in mind that shell constructs behave
like programs:

read line < /etc/group

will read the first line from /etc/group from stdin, and place the
contents in $line.  When placed in a loop like this:

while read line
do
  ...
done < /etc/group

you may well wonder how come read(1) reads from /etc/group, they're
miles part in the code.  The answer is that the loop actually looks
like this:

(
  while read line
  do
    ...
  done
) < /etc/group

Thus, when read(1) tries to read something, its stdin will be connected
to stdin for the loop, which in turn reads from /etc/group, and the loop
will then run until read(1) fails, which it will upon EOF on stdin (ie,
trying to read beyond the end of /etc/group).

The same goes for output:

while read line
do
  echo "$line"
done > /tmp/script.out < /etc/group

will make a copy a /etc/group.

Beware of typical mistake:

while read line < /etc/group
do
  ...
done

This will loop forever, reading the first line of /etc/group again
and again -- the file is opened (at least conceptually) each time
around the loop.  And again for output:

while read line
do
  echo "$line" > /tmp/script.out
done < /etc/group

will put the last line of /etc/group into /tmp/script.out.

Best,

  -- Per


-- 
Gllug mailing list  -  Gllug at linux.co.uk
http://list.ftech.net/mailman/listinfo/gllug




More information about the GLLUG mailing list