[comp.lang.perl] bug with combination of loops and <glob> mechanism

composer@chem.bu.edu (Jeff Kellem) (09/02/90)

The following short script doesn't work properly in perl compiled with these
configurations:

    perl 3.0 pl18:
	Sun 3, SunOS 4.0.3, cc, yacc
    perl 3.0 pl28:
	Sun 3, SunOS 4.0.3, gcc 1.37.1, bison 1.11
	Encore Multimax, UMAX 4.2, gcc 1.37.1, bison 1.11

The script:

	#!/usr/bin/perl
	#
	while (1) {
	    $dir=<~user>;
	    print "DIR=$dir\n";
	}

prints, assuming `~user' == `/foo/bar',

DIR=/foo/bar
DIR=
DIR=/foo/bar
DIR=
 :
 :

It seems that on every other iteration through the loop, no globbing is done
(i.e. no exec of csh occurs).  If you add a few more copies of the globbing
line `$dir=<~user>;' in the script, you should notice the difference in speed
between printing each line.

Note that this also occurs when combined with other looping mechanisms, such
as `foreach', `LABEL: BLOCK goto LABEL', etc.

Any ideas, Larry?

				-jeff

Jeff Kellem
Internet: composer@chem.bu.edu

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (09/03/90)

In article <COMPOSER.90Sep2125802@chem.bu.edu> composer@chem.bu.edu writes:
: The script:
: 
: 	#!/usr/bin/perl
: 	#
: 	while (1) {
: 	    $dir=<~user>;
: 	    print "DIR=$dir\n";
: 	}
: 
: prints, assuming `~user' == `/foo/bar',
: 
: DIR=/foo/bar
: DIR=
: DIR=/foo/bar
: DIR=
:  :
:  :
: 
: It seems that on every other iteration through the loop, no globbing is done
: (i.e. no exec of csh occurs).

That is the intended behaviour.  <> is an iterator meant primarily to
be used within a while.  It's supposed to return false when it's done
giving you the list of globbed filenames, one in this case.  It then
resets and starts over the next time.  You want to say

	($dir) = <~user>;

though if you're just doing it for one user, it ought to be done outside
the loop.  Furthermore, it'll be much more efficient with the current
implementation if you say

	$dir = (getpwnam('user'))[7];

because it won't have to start up csh, and will also be portable to machines
that don't have csh.

If you're doing it for many users, you should slurp it in like this:

	while (($user,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) =
		getpwent) {
	    $dir{$user} = $dir;
	    # anything else you might want to know about them...
	}

Larry