in reply to Re: Regex match on implicit default variable ($_) in a script, not a one liner
in thread Regex match on implicit default variable ($_) in a script, not a one liner

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"

  • Comment on Re^2: Regex match on implicit default variable ($_) in a script, not a one liner

Replies are listed 'Best First'.
Re^3: Regex match on implicit default variable ($_) in a script, not a one liner
by GotToBTru (Prior) on Oct 24, 2015 at 03:56 UTC

    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

      </quote>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.
      </quote>

      You are correct. I am confused as all get out. I think what is getting me the worst is all the short hand and defaults. For instance, is "<>" short hand for "<STDIN>"?.
      What would really help me is if you would rewrite

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

      for me with "-we" in place of "-wple" with all the short hand and defaults removed so I could see exactly what is going on. (You would be my hero as I have asked this elsewhere and have not understood it there either. Mostly very helpful folks show me a better way to write it in a full script. And although greatly appreciated, it does not help me understand exactly what is happening in the "-wple" one liner or how to duplicate it in a full script.)

      Many thanks, -T

        What would really help me is if you would rewrite
        echo -e "abc\ndef\nghi\n" | perl -wlne '! /def/ and print "$_";'
        for me with "-we" in place of "-wple" with all the short hand and defaults removed so I could see exactly what is going on.

        Perl does that for you, at least the part after the pipe char, if you load B::Deparse (comments mine):

        qwurx [shmem] ~> perl -MO=Deparse,-x -wlne '! /def/ and print "$_";' BEGIN { $^W = 1; } # this is -w BEGIN { $/ = "\n"; $\ = "\n"; } # this is -l LINE: while (defined($_ = <ARGV>)) { # and here is what -n does... chomp $_; # this belongs to -l print "$_" unless /def/; } # this belongs to -n too -e syntax OK

        The only line without comment is -e, i.e. your command line script body.

        Here's another example - count lines, invented by Abigail:

        perl -ne '}{ print $.'

        The }{ construct - named eskimo greeting - splits the implicit while loop into a while loop block and a bare block:

        perl -MO=Deparse,-x -ne '}{print$.' LINE: while (defined($_ = <ARGV>)) { # -n (); # script body - a noop } # script body { # script body print $.; # script body } # -n

        The bare block is used to output the current line number of the (special) filehandle ARGV.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        For instance, is "<>" short hand for "<STDIN>"?.

        <> is a very common and useful shorthand notation. You'll often encounter this, and I recommend getting familiar with it, it really comes in handy every time you want to process user-supplied input.

        The short version is that it Does What You Mean; I/O Operators has the nitty-gritty:

        The null filehandle <> is special: it can be used to emulate the behavior of sed and awk, and any other Unix filter program that takes a list of filenames, doing the same to each line of input from all of them. Input from <> comes either from standard input, or from each file listed on the command line. Here's how it works: the first time <> is evaluated, the @ARGV array is checked, and if it is empty, $ARGV[0] is set to "-", which when opened gives you standard input. The @ARGV array is then processed as a list of filenames. The loop

        while (<>) { ... # code for each line }

        is equivalent to the following Perl-like pseudo code:

        unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } }

        except that it isn't so cumbersome to say, and will actually work. [...]

        For the various flags to the perl executable, see perlrun. -n and -p put certain loops around your code, allowing you to write only the code inside the loop (very useful for one-liners on the command line); -l auto-chomps your input, which is useful in much the same situations.

Re^3: Regex match on implicit default variable ($_) in a script, not a one liner
by Athanasius (Archbishop) on Oct 24, 2015 at 04:02 UTC

    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,

      I am now able to exclude and reform $B, but I can't do it the other way (include only "def"). Isn't "while" suppose to be the opposite of "until"?

      #!/usr/bin/perl use strict; use warnings; use diagnostics; my $B = ""; my $A = "abc def ghi "; while ( $A =~ m{(.+)}g ) { $B .= "$1\n" unless $1 =~ /def/; } print "\$B = \n$B\n"; $B = ""; while ( $A =~ m{(.+)}g ) { $B .= "$1\n" while $1 =~ /def/; } print "\$B = \n$B\n";

      $B =

      abc

      ghi

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

      Now what am I doing wrong?

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

        Yes, but you want the “opposite” (actually, the negation) of unless, which is simply if. See perlsyn#Statement-Modifiers.

        But there is another problem: $1 refers to the first capture in the most recent regular expression match. In the expression:

        $B .= "$1\n" unless $1 =~ /def/;

        the concatenation $B .= "$1\n" occurs only if the regex match $1 ~ /def/ fails; in which case, there is no match, so the most recent match is still the one from the while loop regex. But in the expression:

        $B .= "$1\n" if $match =~ /def/;

        the concatenation occurs only if the new match succeeds; in which case, $1 is overwritten. You can fix this by assigning the value of $1 to a temporary variable:

        while ($A =~ m{(.+)}g) { my $capture = $1; $B .= "$capture\n" if $capture =~ /def/; }

        Hope that helps,

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

      I am trying to create a multiline $B from $A. How do I reassemble $B?