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

I Have been playing around with this for a while now but cant seem to get the if statement to run the correct subroutine. The script runs trough but only seems to run the subroutine which adds the symbolic links (&addlinks) no matter what is in STDIN I can supply the full code if necessary. Help much appreciated.
#!/usr/bin/perl -w use Cwd; my $dir = getcwd; print "Would you like to add or remove symbolic links?\n"; my $answer = <STDIN>; chomp $answer; if ($answer eq "add" || "a") { &addlinks; } elsif ($answer eq "remove" || "r") { &rmlinks; } else {exit 0; }

Replies are listed 'Best First'.
Re: Subroutines within if statements
by kyle (Abbot) on Feb 21, 2008 at 22:16 UTC

    I think you mean:

    if ($answer eq "add" || $answer eq "a") { &addlinks; } elsif ($answer eq "remove" || $answer eq "r") { &rmlinks; } else { exit 0; }

    You're probably better off calling those as addlinks() and rmlinks() until you understand how the &sub calls are special (see perlsub).

    Also, I recommend that you use strict; use warnings; until you know why you might not want strict and warnings.

      Nowadays you can use

      use 5.010; if ("$answer" ~~ [ 'add', 'a' ]) { ... }
      I explicitly stringify $answer because if $answer happens to be something else (like an object) the ~~ operator will act differently and I don't want that. On the contrary, I want to allow objects that may stringify to "add" or "a".

      lodin

      ...until you know why you might not want strict and warnings.
      Why might I not want strict and warnings?

      I get twitchy seeing no warnings in a small block. When I see either commented out at the top of a script I hide behind the sofa. :-)

      What is it I don't know yet? Is there a secret handshake? :-)

        Why might I not want strict and warnings?

        I haven't written any significant code without them since I learned of them. (I write perl -e without them.) I don't have a case where I wouldn't want them.

        That said, I could imagine code that produces spurious warnings. I could further imagine some PHB who wants no error messages in a log somewhere.

        I've heard some say they turn off strict and warnings in production to avoid some overhead. I personally think this is a lousy way to gain performance.

        Like you, I don't like to see code without strict and warnings. I don't want to work on it. Nevertheless, other programmers have their own minds, and I want to respect that.

      That's great as soon as I saw your code I knew where I went wrong. :( Bit of along day :)
Re: Subroutines within if statements
by runrig (Abbot) on Feb 21, 2008 at 22:10 UTC
    "a" is always true, so your code always calls addlinks().
Re: Subroutines within if statements
by Fletch (Bishop) on Feb 21, 2008 at 22:22 UTC

    And the B::Deparse module can be handy when trying to figure out why when something's not behaving the way you expect. I show running over code given in a shell here-doc, but you can do the same thing to code in a file via perl -MO=Deparse,-p my_file.plx.

    $ perl -MO=Deparse,-p <<'EOT' if ($answer eq "add" || "a") { &addlinks; } elsif ($answer eq "remove" || "r") { &rmlinks; } else {exit 0; } EOT if ((($answer eq 'add') or 'a')) { &addlinks; } elsif ((($answer eq 'remove') or 'r')) { &rmlinks; } else { exit(0); } - syntax OK

    In the explicitly parenthesized version you can see exactly what your comparisons really mean to Perl.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Subroutines within if statements
by Joost (Canon) on Feb 21, 2008 at 22:17 UTC
Re: Subroutines within if statements
by johngg (Canon) on Feb 21, 2008 at 22:22 UTC
    Another way to do it would be to use a regular expression match.

    use strict; use warnings; print "Would you like to add or remove symbolic links?\n"; chomp( my $answer = <STDIN> ); if( $answer =~ m{^a(?:dd)?$} ) { addlinks(); } elsif( $answer =~ m{^r(?:emove)?$} ) { rmlinks() } else { exit( 0 ); }

    Cheers,

    JohnGG

      A simple and more flexible (for the user) way would be to reverse the args:
      if ( "add" =~ /^\Q$answer/ ) { ... }
      Update: you can even precompile the regex for multiple uses:
      my $ans = qr/^\Q$answer/; if ( "add" =~ /$ans/ ) { ... } elsif ( "remove" =~ /$ans/ ) { ... }

      chomp isn't needed if you use "$" in your regexp.

      Conversely, "\z" is sufficient if chomp is used.

Re: somewhat OT: Subroutines within if statements
by ww (Archbishop) on Feb 21, 2008 at 22:40 UTC

    OT, but, your exit 0; may leave users -- those who enter "rm" for example -- believing your script failed. Better to tell them what went wrong, now that above responders have provided direct answers to your OP.

    It may be well to insert something like line 2 (below):

    else { print "Invalid response: use ONLY one of the following add, a, rem +ove, r\n"; exit 0; }

    Test your opens, regex captures and the like before using them; TELL your users (or at least, give them a hint) how they screwed up.

      In fact you probably shouldn't use exit 0 for an error at all. Better to use die $message instead.

      Giving a non-zero exit code (as die() does) on error makes combining scripts in shell scripts / one-liners a lot easier:

      my-shell$ check-this-config-file.pl && then-stop-this-server && then-d +o-a-lot-of-stuff.pl && then-start-that-server
      And yes I do this a lot.

Re: Subroutines within if statements
by toolic (Bishop) on Feb 21, 2008 at 22:19 UTC
    Elaborating on runrig's answer, you probably meant to use:
    if ($answer eq "add" || $answer eq "a") {

    Same goes for your elsif.