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

Dear Monks...

I've come across a script (in a Perl textbook) that fails to run properly, and I'm requesting some help troubleshooting it. The actual script:

#!/usr/bin/perl # check command-line for validity die "syntax: $0 user passwd [-r | -a task priority]\n\t" if ! defined $ARGV[1]; # validate username/password pair $uname = shift; $passwd = shift; # open user data file open UDATA, "<todo.users" || die "couldn't open user data file."; # read user data into a hash while ($line = <UDATA>) { chomp $line; ($u, $p) = split /:/, $line; $ubase{$u} = $p; } close UDATA; # find command-line args in hash or exit die "cannot find user $uname\n\t" if ! defined $ubase{$uname}; die "cannot validate user password\n\t" if $passwd ne $ubase{$uname}; # check for runtime options (-r or -a) if (! defined $ARGV[0]) { $mode = "report"; } elsif ($ARGV[0] =~ /^-r/) { $mode = "report"; } elsif ($ARGV[0] =~ /-a/) { $mode = "add"; $dummy = shift; $newtask = shift; $priority = shift; } else { $mode = "report"; } # get existing task data open TDATA, "<todo.tasks" || die "couldn't open task data file\n\t"; while ($line = <TDATA>) { chomp $line; push @tlist, $line; } # here's a cheaper way # @tlist = <TDATA>; close TDATA; # write report if we're in that mode if ($mode eq "report") { foreach $t (@tlist) { print "$t\n" if $t =~ $uname; } } # print out new data file if we're in that mode if ($mode eq "add") { $newitem = join ":", ($uname, $newtask, $priority); push @tlist, $newitem; foreach $line (@tlist) { print "$line\n"; } }
The supporting todo.users file:
larry:lingo tom:tonic ellie:plasma
The supporting todo.tasks file:
larry:finish autostory program:3 larry:read about file i/o:2 tom:order 12 gallons of Vitalis:1 ellie:find planet-related websites:2 tom:get more paper for clipboard:3 randal:write roster management program:2
I'm curious why this fails with:
cannot validate user password at todo001.pl line 23.
Would someone please explain?

Thanks!

Replies are listed 'Best First'.
Re: Unable to run or troubleshoot a script...
by GrandFather (Saint) on Jun 26, 2007 at 02:37 UTC

    If I trim the cruft, use DATA (because this is a sample and I don't want to use external files), provide the user and password as constants (because this is a sample and I don't want to use STDIN), then:

    #!/usr/bin/perl # read user data into a hash while ($line = <DATA>) { chomp $line; ($u, $p) = split /:/, $line; $ubase{$u} = $p; } my $uname = 'larry'; my $passwd = 'lingo'; # find command-line args in hash or exit die "cannot find user $uname\n\t" if ! defined $ubase{$uname}; die "cannot validate user password\n\t" if $passwd ne $ubase{$uname}; print "Validated user name and password\n"; __DATA__ larry:lingo tom:tonic ellie:plasma

    Prints:

    Validated user anme and password

    as expected. Perhaps you didn't provide a correct password?

    More important is to be aware of a couple of bad things this example is teaching you. First, always use strictures (use strict; use warnings;). The textbook example doesn't. Second, use the three parameter open because it's safer and clearer. Often too it's helpful to give the user the system generated error for a failed operation - die "couldn't open task data file: $!\n\t" (note the $!).


    DWIM is Perl's answer to Gödel
      It appears the problem is related to my downloaded todo.users file, which, opened in the editor, shows as:
      larry:lingo tom:tonic ellie:plasma [ Read 4 lines (Converted from DOS format) ] ^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut + Text ^C Cur Pos ^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnC +ut Text ^T To Spell
      The issue relates the message at the bottom of the editor screen: Read 4 lines (Converted from DOS format). Having copied the same list of users:passwords to a fresh editor screen, the script runs as anticipated.

      In what way does the downloaded "DOS format" disrupt this file?

      Thanks!

        Most likely a difference in line end characters. "DOS" uses crlf where *nix uses lf and Mac uses cr.

        chomp (by default) removes the line end sequence used by the host OS so if you are running *nix and you have a file containing crlf line ends then you will get the cr left at the end of the line causing the password match to fail.


        DWIM is Perl's answer to Gödel
Re: Unable to run or troubleshoot a script...
by naikonta (Curate) on Jun 26, 2007 at 02:37 UTC
    It works fine for me,
    $ perl todo.pl larry lingo larry:finish autostory program:3 larry:read about file i/o:2 $ perl todo.pl tom tonic tom:order 12 gallons of Vitalis:1 tom:get more paper for clipboard:3 $ perl todo.pl ellie plasma ellie:find planet-related websites:2
    Can you add the username in the error message so you'd know which user failed the password validation?
    die "cannot validate user password for $uname\n\t" if $passwd ne $ubase{$uname};
    Also, do you have problem with strict and warnings?

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

      This shows one of the username password combos I tried, and its result with warnings turned on:
      ~/bin/lowe_book/ch07 $ perl todo001.pl ellie plasma Name "main::dummy" used only once: possible typo at todo001.pl line 36 +. cannot validate user password at todo001.pl line 23.
      I have no trouble with using strict and warnings, but this is code as it appears in the text I'm studying.
Re: Unable to run or troubleshoot a script...
by chrism01 (Friar) on Jun 26, 2007 at 06:52 UTC
    I agree with Grandfather & anonymous monk, that's awful code. You might want to think about another book.
    Also, use 'or die "...$!\n";' not '|| die ...'.
    Note that in the lines:
    # here's a cheaper way # @tlist = <TDATA>;
    you'll still need to chomp the array before using it

    Cheers
    chris

      chrism01 wrote:

      You might want to think about another book.

      I'm currently using 4 books:

      Perl Workbook - Lowe
      Beginning Perl - Lee
      Learning Perl - Schwartz
      Intermediate Perl -Schwartz

      I use the Lowe book because of the multitude of situational problems and suggested code solutions it presents. It's regrettable that some of the code examples are somewhat lacking. Is there an additional interactive book I should consider?

      Thanks for the comments!

A reply falls below the community's threshold of quality. You may see it by logging in.