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

Hi All,

How do I use // except with a variable in a script and not a pipe and a one liner?

echo -e "abc\ndef\nghi\n" | perl -wlne '! /def/ and print "$_";'

abc ghi

But I am having a hard time figuring out how to do it in a full script. How do I use // in a full script?

#!/usr/bin/perl use strict; use warnings; use diagnostics; my $A="abc\ndef\nghi\n"; (my $B = $A ) =~ ! /def/; print "$B";

Use of uninitialized value $_ in pattern match (m//) at ./ExtractTest.pl line 8 (#1

What am I doing wrong

Many Thanks, -T

Replies are listed 'Best First'.
Re: Regex match on implicit default variable ($_) in a script, not a one liner
by NetWallah (Canon) on Oct 24, 2015 at 03:13 UTC
    The statement:
    ! /def/
    compares "def" with $_ .

    $_ is defined in your one-liner (By the existance of -n in the perl command)

    But $_ is undefined in the "full script".

    Perhaps you meant:

    (my $B = $A ) !~ /def/ and print $B;
    which compares the contents of $A/$B.

            The best defense against logic is ignorance.

      I want to remove the middle line from $A. Same as I did with the one liner.

      What is desired:

      Before: $A="abc\ndef\nghi\n"

      After: $B="abc\nghi\n"

        You aren't aware of what the switches on your one-liner are doing for you. See perlrun

        The -n is the most important one. It applies a while(<>) { ... } loop around your code. So, it is taking your input string, splitting it into lines, assigning each value in turn to $_, and then executing the body of your one-liner for each value. In a program, you have to specify that.

        #!/usr/bin/perl use strict; use warnings; use diagnostics; my $A="abc\ndef\nghi\n"; my @list = split /\n/,$A; while (<@list>) { ! /def/ and print }

        Updated: my most literal attempt didn't work, putting the split inside the while condition. So I use split to create an array. That works better.

        Dum Spiro Spero

        Hello Todd,

        Here’s another approach, using the /g modifier in scalar context and relying on the fact that . in a regex matches any character except a newline:

        use strict; use warnings; my $A = "abc\ndef\nghi\n"; while ($A =~ /(.+)/g) { print "$1\n" unless $1 =~ /def/; }

        Output:

        13:59 >perl 1419_SoPW.pl abc ghi 14:00 >

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Regex match on implicit default variable ($_) in a script, not a one liner
by BrowserUk (Patriarch) on Oct 24, 2015 at 05:29 UTC

    Like this?:

    #!/usr/bin/perl use strict; use warnings; use diagnostics; my $A = "abc\ndef\nghi\n"; ( my $B = $A ) =~ s/def\n//g; print "$B"; __END__ C:\test>1145825.pl abc ghi

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
      or more compactly using the /r modifier : update: ($B is not needed)
      $A =~ s/def\n//gr; print $A;

      Thank you, but unfortunately no.
      The "def" will only be a part of the line. If "def" occurs anywhere in the line I want it included.

      #!/usr/bin/perl # full script the following one liner: # $ echo -e "abc\ndef\nghi\n" | perl -wlne '! /def/ and print "$_";' # abc # ghi use strict; use warnings; use diagnostics; my $B = ""; my $A = "abcdef fhijkl mnopqr "; while ( $A =~ m{(.+)}g ) { $B .= "$1\n" unless $1 =~ /ijk/; } print "\$B = \n$B\n"; $B = ""; while ( $A =~ m{(.+)}g ) { $B .= "$1\n" while $1 =~ /ijk/; } print "\$B = \n$B\n";

      $B =
      abcdef
      mnopqr
      Use of uninitialized value $1 in concatenation (.) or string at ./ExtractTest.pl line 26 (#1)

      Isn't "while" suppose to be the opposite of "unless"?

        Isn't "while" suppose to be the opposite of "unless"?

        No it isn't. "while" is the opposite of "until". The opposite of "unless" is "if". All of this is in the fine documentation of Compound Statements.

        The "def" will only be a part of the line. If "def" occurs anywhere in the line I want it included.

        This perhaps?:

        #!/usr/bin/perl use strict; use warnings; use diagnostics; my $A = "abcdef fhijkl mnopqr redefine "; ( my $B = $A ) =~ s[(^.+\n)][ my $x = $1; $x !~ /def/ ? '' : $x ]gme; print "$B"; __END__ C:\test>1145825.pl abcdef redefine

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Regex match on implicit default variable ($_) in a script, not a one liner
by Anonymous Monk on Oct 24, 2015 at 04:36 UTC

    Basic debugging checklist says to find out what perl thinks of your program use B::Deparse, like  perl -MO=Deparse,-p ...

    So

    $ perl -MO=Deparse,-p -wlne " ! /def/ and print qq{$_}; " BEGIN { $^W = 1; } BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined(($_ = <ARGV>))) { chomp($_); (/def/ or print("$_")); } -e syntax OK
Re: Regex match on implicit default variable ($_) in a script, not a one liner
by mr_ron (Deacon) on Oct 24, 2015 at 17:20 UTC

    I came up with something that seems to match your pipe/one liner closely. It doesn't chomp but you don't match against the end of line so I don't think that matters much.

    use strict; use warnings; my $A="abc\ndef\nghi\n"; # remember matching is greedy but # without /s modifier '.' does not match \n my $B = join('', grep { ! /def/ } $A =~ /(.*\n)/g); print $B;
    Ron
Re: Regex match on implicit default variable ($_) in a script, not a one liner
by james28909 (Deacon) on Oct 24, 2015 at 14:52 UTC
    I want to remove the middle line from $A. Same as I did with the one liner.
    What is desired:
    Before: $A="abc\ndef\nghi\n"
    After: $B="abc\nghi\n"

    Heres another way, which you can also iterate through the array easily (once you have built one ofcourse) :)

    use strict; use warnings; my @array = "abc\ndef\nghi\n"; print $1 . $3 if $array[0] =~ /(.*)(\ndef)(.*)/s;
      I do not see your point about using an array here, since you are not really using an array but just one element of your array, so that a scalar value would just work the same way:
      my $scalar = "abc\ndef\nghi\n"; print $1 . $3 if $scalar =~ /(.*)(\ndef)(.*)/s;

        I was trying to duplicate what the one liner does, so I wanted to keep it as a string.
        I finally figured it out: preserve $1 and use "if" instead of "while":

        #!/usr/bin/perl # full script the following one liner: # $ echo -e "abc\ndef\nghi\n" | perl -wlne '! /def/ and print "$_";' # abc # ghi use strict; use warnings; use diagnostics; my $C; my $B = ""; my $A = "abcdef fhijkl mnopqr "; while ( $A =~ m{(.+)}g ) { $B .= "$1\n" unless $1 =~ /ijk/; # $B .= "$1\n" unless $1 =~ /xyz/; } print "\$B = \n$B\n"; $B = ""; while ( $A =~ m{(.+)}g ) { $C = $1; $B .= "$C\n" if $C =~ /ijk/; } print "\n\$B = \n$B\n";

        $B =
        abcdef
        mnopqr


        $B =
        fhijkl

        Thank you for all the help! -T