http://www.perlmonks.org?node_id=714766

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

Hi

I would like to either use some options to set a value or set that value according to the value in a particular file

I start off by setting the default value

my $test = 1;

Using Getopt::Std and a my %opt; hash I then check for two single letter options, s or t with the latter superceding the former.

getopt('st',\%opt); if ($opt{'t'}) { $test = 1; ## testing } elsif ($opt{'s'}) { $test = 0; ## not testing }
I then try to detect whether either of the hash values are defined.
if ( (!(defined($opt{'s'}))) && (!(defined($opt{'t'}))) ) { ## neither option was used let's check sitetest file for a test valu +e printf "Reading from sitetest file\n"; open(TEST,"< test") or die "Can't open file test \n"; my $line = <TEST>; close STEST; print $line."\n"; if ($line =~ /0/) {$test = 0;} }

which isn't working .. the program continues to read from file. Is this because I am using a hash and the second I mention a hash key the key exists or something else? How could I get this to work?

I also don't like the (!(defined($anyvarhere))) construct. Is there a better way to detect the non-existence of a hash key in particular and, in general terms, the undefinedness of a variable?

Replies are listed 'Best First'.
Re: Detecting an undefined hash key
by moritz (Cardinal) on Oct 01, 2008 at 10:33 UTC
    I also don't like the (!(defined($anyvarhere))) construct. Is there a better way to detect the non-existence of a hash key
    exists.
Re: Detecting an undefined hash key
by JavaFan (Canon) on Oct 01, 2008 at 10:33 UTC
    You seem to be mixing up terms.

    Hash keys are used as an index in the hash. Hash keys are always strings, and are always defined. There's no such thing as an undefined hash key.

    Having said that:

    if (exists $hash{key}) { ... } # True if there's a value for 'ke +y' if (defined $hash{key}) { ... } # True if there's a value for 'ke +y' and the value is defined. if ($hash{key}) { ... } # True if there's a value for 'ke +y' and the value is true.
    defined is the test to use to test whether something is defined. To test the existance of a hash key, use exists.
Re: Detecting an undefined hash key
by toolic (Bishop) on Oct 01, 2008 at 13:33 UTC
    You have omitted one key piece of information: how are you calling your program?

    For example, do you call it with "-t" or with "-t 1"? There is a difference.

    I have added some print statements to your code to help debug:

    > cat 714766.pl #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Getopt::Std; #print 'ARGV ',Dumper(\@ARGV); my $test = 1; my %opt; getopt('st',\%opt); #print 'opt ',Dumper(\%opt); if ($opt{'t'}) { $test = 1; ## testing #print "set test=1 again\n"; } elsif ($opt{'s'}) { $test = 0; ## not testing #print "set test=0\n"; } #print "test=$test\n"; if ( (!(defined($opt{'s'}))) && (!(defined($opt{'t'}))) ) { print "neither -t or -s used\n"; } else { print "either -t or -s used\n"; }

    Now some sample program calls (5.8.8 on linux):

    > ./714766.pl neither -t or -s used > > ./714766.pl -t neither -t or -s used > > ./714766.pl -t 0 either -t or -s used > > ./714766.pl -t 1 either -t or -s used > > ./714766.pl -s 5 either -t or -s used

    Data::Dumper can help you understand what is in %opt

    Update: It seems to me that the documentation for Getopt::Std is incorrect:

    getopt() and getopts() will also accept a hash reference as an optional second argument. Hash keys will be x (where x is the switch name) with key values the value of the argument or 1 if no argument is specified.
    If no argument is specified for getopt, the hash key is NOT set to 1 (Dumper shows it as 'undef').

      Wow, wow and double wow

      It would seem that s and t are indeed strange in Getopt::Std.

      There is much for my simple mind to digest in all these replies and I thank you all for the tips and nudges on exists and Data::Dumper

      I did think that, if one expected to use -t <value> on the command line then the expected syntax for getopt would be getopt('st:',\%opt); with the : indicating a required value for the argument.

      I'll have to check the documentation on that but this did mean I thought the lack of a : would make it clear no value was being supplied for aither the s or t arguments.

        It would seem that s and t are indeed strange in Getopt::Std.
        I disagree. There is no evidence which supports the claim that s and t are strange in any way. I tried using a and b instead of s and t in my example, and the behavior is the same. Give it a try.
        I did think that, if one expected to use -t <value> on the command line then the expected syntax for getopt would be getopt('st:',\%opt); with the : indicating a required value for the argument.
        The getopts function (notice the "s" on the end) uses the ":" syntax, not the getopt function. So, it seems that, contrary to the docs, getopts requires you to supply a <value> with each switch.
Re: Detecting an undefined hash key
by GrandFather (Saint) on Oct 01, 2008 at 10:52 UTC

    Although the Getopt::Std documentation doesn't seem to mention it, -t and -s are special. Consider:

    use strict; use warnings; use Getopt::Std; use Data::Dump::Streamer; testSwitches (qw(-p -q)); testSwitches (qw(-s)); testSwitches (qw(-t)); testSwitches (qw(-s -t)); testSwitches (qw(-p)); sub testSwitches { local @ARGV = @_; my %opt; my $test; print join (' ', @ARGV), "\n"; getopt ('st', \%opt); Dump \%opt; print "\n"; }

    Prints:

    -p -q $HASH1 = { p => 1, q => 1 }; -s $HASH1 = { s => undef }; -t $HASH1 = { t => undef }; -s -t $HASH1 = { s => '-t' }; -p $HASH1 = { p => 1 };

    Is this some sort of *nix convention perhaps?

    Note that you could use exists for your test instead of defined. You could also reduce the number of parenthesis to make the code more readable:

    if (! exists $opt{s} and ! exists $opt{t}) {

    Update: Struck silliness. Left code as a nice template for playing with/testing/demonstrating option processing.


    Perl reduces RSI - it saves typing
      Nothing special going here. But with 'getopt ("st")', you declare -s and -t to take an argument. So, if you just provide -s, the argument is undef. If you provide -s -t, -t is the argument of -s.

        Doh! /me slaps forehead with a wet fish!


        Perl reduces RSI - it saves typing
Re: Detecting an undefined hash key
by massa (Hermit) on Oct 03, 2008 at 14:55 UTC
    what you want is getopts (with an S), not getopt:
    use strict; use warnings; use Getopt::Std; getopts 'st', \my %opt; my $test = $opt{t} || !$opt{s}; unless( $opt{t} || $opt{s} ) { print "Reading from site test file\n"; open my $t, '<', 'test' or die "Can't open site test file: $!"; local $_ = <$t>; print; $test = ! /0/ ### I would rather say $test = !!$_ }
    []s, HTH, Massa (κς,πμ,πλ)