Parsing grep -n
with AWK
grep -n -o '[AZ]\{2\}-[A-Z0-9]\{4\}' file | awk -F: -vi=0 '{ printf("%s%s", i ? (i == $1 ? " " : "\n") : "", $2) i = $1 }'
The idea is to combine the lines with the output of grep -n
:
1:EU-1C0A 1:TM-0401 2:MG-7688 2:DN-0A00 2:DN-0A52 2:MG-3218 3:DN-0A00 3:DN-0A52 4:EU-1C0A 4:MG-7688
by line numbers. AWK initializes the field separator ( -F:
and the variable i
( -vi=0
), then processes the output of the grep
command line.
It prints a character based on a conditional expression that checks the value of the first field of $1
. If i
is zero (first iteration), it prints only the second field $2
. Otherwise, if the first field is i
, it prints a space, otherwise a new line ( "\n"
). After a space / new line, a second field will be printed.
After printing the next fragment, the value of the first field is stored in i
for the following iterations (lines): i = $1
.
Perl
Parsing grep -n
in Perl
use strict; use warnings; my $p = 0; while (<>) { /^(\d+):(.*)$/; print $p == $1 ? " " : "\n" if $p; print $2; $p = $1; }
Usage: grep -n -o '[AZ]\{2\}-[A-Z0-9]\{4\}' file | perl script.pl
grep -n -o '[AZ]\{2\}-[A-Z0-9]\{4\}' file | perl script.pl
.
Single line
But Perl is actually so flexible and powerful that you can completely solve the problem with a single line:
perl -lne 'print @_ if @_ = /([AZ]{2}-[AZ\d]{4})/g' < file
I saw a similar solution in one of the answers here. However, I decided to publish it as it is more compact.
One of the key ideas is to use the -l
switch, which
- automatically compresses the input separator
$/
; - sets the output record separator
$\
to $/
(by default, this is a new line)
The separator value of the output record, if specified, is printed after the last argument passed to print
. As a result, the script prints all matches ( @_
in particular), followed by a new line.
The variable @_
usually used as an array of subroutine parameters. I used it in a script just for the sake of brevity.