Home > Software design >  Perl grep-like one-liner with regex match condition and assignment?
Perl grep-like one-liner with regex match condition and assignment?

Time:11-30

Say I have this file:

cat > testfile.txt <<'EOF'
test1line
test23line
test456line
EOF

Now, I want to use perl in a "grep like" manner (a one-liner expression/command with file argument, which dumps output to terminal/stdout), such that I match all of the numbers in the above lines, and I make them into zero-padded three digit representation. So, I tried this to check if matching generally works:

perl -nE '/(.*test)(\d )(line.*)/ && print "$1 - $2 -$3\n";' testfile.txt
#test - 1 -line
#test - 23 -line
#test - 456 -line

Well, that works; so now, I was thinking, I'll just call sprintf to format, assign that to a variable, and print that variable instead, and I'm done; unfortunately, my attempt there failed:

perl -nE '/(.*test)(\d )(line.*)/ && $b = sprintf("d", $2); print "$1 - $b -$3\n";' testfile.txt
#Can't modify logical and (&&) in scalar assignment at -e line 1, near ");"
#Can't modify pattern match (m//) in scalar assignment at -e line 1, near ");"
#Execution of -e aborted due to compilation errors.

Ok, so something went wrong there. As far as I can tell from the error messages, apparently mixing logical AND (&&) and assignments like in the above one-liner do not work.

So, how can I have a Perl one-liner where a regex-condition is checked; and if match is detected, a series of commands are executed, which may involve one or more assignments, and conclude with a print?


EDIT: found an invocation that works:

perl -nE '/(.*test)(\d )(line.*)/ && printf("$1d$3\n", $2);' testfile.txt
#test001line
#test023line
#test456line

... but I'd still like to know how to do the same via sprintf and assignment to variable.

CodePudding user response:

Precedence issue.

/.../ && $b = ...;

means

( /.../ && $b ) = ...;

You could use

/.../ && ( $b = ... );
/.../ && do { $b = ...; };
/.../ and $b = ...;
$b = ... if /.../;

But there's a second problem. You call print unconditionally.

perl -ne'printf "%s-d-%s\n", $1, $2, $3 if /(.*test)(\d )(line.*)/'
  •  Tags:  
  • perl
  • Related