To exactly match the final sequence in square brackets:
perl -alne 'm/S?SELECT.*?(?=\[ \S+ @ \S+ \]$)/ && print $&;' file
outputs
SELECT PRINTER.LOCS WITH SHIP.TICK.BR = "15"
SSELECT PRODUCT BY STK.LN.SEQ
SELECT ORDER.QUEUE WITH &INDEX&.STATUS = "S~S]" "H~S]" "A~S]" "M~S]" AND WITH &INDEX&.SBR "51 17~]"
SSELECT UD.VIEWS WITH &INDEX& = "ORDERENTRY.ORDERENTRY~0"
You can always do:
tac < fileName | sed '/EndPattern/,$!d;/StartPattern/q' | tac
If your system doesn't have GNU tac
, you may be able to use tail -r
instead.
You can also do it like:
awk '
inside {
text = text $0 RS
if (/EndPattern/) inside=0
next
}
/StartPattern/ {
inside = 1
text = $0 RS
}
END {printf "%s", text}' < filename
But that means reading the whole file.
Note that it may give different results if there's another StartPattern
in between a StartPattern
and the next EndPattern
or if the last StartPattern
does not have an ending EndPattern
or if there are lines matching both StartPattern
and EndPattern
.
awk '
/StartPattern/ {
inside = 1
text = ""
}
inside {text = text $0 RS}
/EndPattern/ {inside = 0}
END {printf "%s", text}' < filename
Would make it behave more like the tac+sed+tac
approach (except for the unclosed trailing StartPattern
case).
That last one seems to be the closest to your edited requirements. To add the warning would simply be:
awk '
/StartPattern/ {
inside = 1
text = ""
}
inside {text = text $0 RS}
/EndPattern/ {inside = 0}
END {
printf "%s", text
if (inside)
print "Warning: EOF reached without seeing the end pattern" > "/dev/stderr"
}' < filename
To avoid reading the whole file:
tac < filename | awk '
/StartPattern/ {
printf "%s", $0 RS text
if (!inside)
print "Warning: EOF reached without seeing the end pattern" > "/dev/stderr"
exit
}
/EndPattern/ {inside = 1; text = ""}
{text = $0 RS text}'
Portability note: for /dev/stderr
, you need either a system with such a special file (beware that on Linux if stderr is open on a seekable file that will write the text at the beginning of the file instead of the current position within the file) or an awk
implementation that emulates it like gawk
, mawk
or busybox awk
(those work around the Linux issue mentioned above).
On other systems, you can replace print ... > "/dev/stderr"
with print ... | "cat>&2"
.
Best Answer
...would do the job portably by
d
eleting all lines which do!
not fall within the range, thenq
uitting the first time it encounters the end of the range. It does not fail for P2 preceding P1, and it does not require GNU specific syntax to write simply.