Succinct Way to Print All Lines Up Until The Last Line That Matches a Given Pattern

Perl: append a line after the last line that match a pattern (but incrementing part of the pattern)

/usr/bin/perl -i -pe 'BEGIN{undef $/;}; s/((param\.(\d+)=\S+\s)+)/$1."param.".($3+1)."=valueXXX\n"/ems' /tmp/myfile.txt

How can I print all the lines between the previous and next empty lines when a match is found?

Wow, you guys really like doing a lot of work in those answers. Remember, in text processing, Perl makes the easy things easy (and the hard things possible). If you're doing a lot of work for something that's easy to explain, you're probably missing the easy way. :)

Just redefine a line to be a paragraph and print the matching paragraphs as you read them. You can change Perl's idea of a line by setting the input record separator, $/, to be the line-ending that you want. When you use the line input operator, you'll get back everything up to and including what is in $/. See perlvar for the details on Perl special variables:

#!perl

{
local $/ = "\n\n";

while( my $group = <DATA> ) {
print $group if $group =~ /\Q**QUERY**/;
}
}

__DATA__
mascot
friend
ocean

parsimon
**QUERY**
apple

jujube

apricot
maple
**QUERY**
rose
mahonia

ghostdog74 posted his one-liner version, which I modified slightly:

perl -ne "$/=qq(\n\n); print if /\Q**QUERY**/" fileA fileB ...

perl has a special command-line switch for this, though. You set the input record separator with -0, and if you set it to 0, it means you're setting it to use the paragraph mode:

perl -00 -ne "print if /\Q**QUERY**/" fileA fileB ...

The perlrun shows you all the nifty things you can do on the command line.

Subset File based One Line and Printing Other lines Until it reaches next line

with gawk record separator, perl should have similar...

$ awk -v RS='(^|\n)#' '$7<-34.4{printf "%s", rt $0} {rt=RT}' file

# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S

note that you want < since the sign is negative. Since we use # as the record delimiter, field number is one less.

We define the record separator as the leading # or after new line. Normally RS is between records but here it's leading the records. That's why we capture the matched record separator RT and assign to a variable to be used in the (next) record. Also the RT includes the new line, that's why printf doesn't have one.

Print lines between two regex using sed

awk '/pattern/{p=1;print;next} p&&/^##/{p=0};p' file

take the "Screenshot" as example:

kent$  awk '/^## Screenshot/{p=1;print;next} p&&/^##/{p=0};p' file
## Screenshots ##

1. line 1
2. line 2
3. line 3
4. line 4

EDIT add explanation

awk '/^## Screenshot/{p=1;print;next} : if match pattern, set p=1,print the line,read next line,(stop processing following scripts)
p&&/^##/{p=0} : if p==1 and match /##/ again (next section), set p=0
;p' file : if p==1, print the line

sed only

sed -n '/## Screensh/,/##/{/Scree/{p;n};/##/{q};p}' file

EDIT2 add explanation to sed cmd

-n                 -> not print
'/## Screen/, /##/ -> match range, I guess you knew it already
{ -> if in this range
/Scree/ -> and line matches /Screenshot/
{p;n}; -> do print line, and read next row (skip doing rest processing)
/##/ -> if line matches "##"
q; -> quit, we have done all printing
p -> if we come to here, print the line
}

Print previous line along with matched line

You are on right path, You forgot to print the current line simply do.

awk '
/pattern/{
if(prev) { print prev ORS $0 }
if(FNR==1){ print }
next
}
{
prev=$0
}
' Input_file

I have also taken care of 1st first line here, in case pattern comes in very first line then it will simply print that line, since there is no previous line.

Explanation: Adding detailed explanation for above.

awk '                                 ##Starting awk program from here.
/pattern/{ ##Checking for specific pattern here.
if(prev) { print prev ORS $0 } ##Checking if prev is NOT NULL then print prev newline current line.
if(FNR==1){ print } ##Checking if its first line then simply print the line.
next ##next will skip all further statements from here.
}
{
prev=$0 ##Setting prev to current line here.
}
' Input_file ##Mentioning Input_file name here.

how do I use awk to print starting at pattern, end at another pattern then exit?

Currently with the ranges you get a partial match for 50000 in 150000 and 60000 in 160000 and you are printing:

50000

55000

60000

and

150000

160000

If you want to match the whole line without partial matches, you can use anchors for the start and the end pattern.

awk '/^50000$/,/^60000$/' file

Concise AWK for pattern matching a column while keeping header for each file specified

With your shown samples, could you please try following. You need not to run a bash loop to run awk code in it, awk is very much capable to read all the files in a single shot by itself. Following code will create output file names with eg--> file1.txt.add and only .txt format files are being passed as an input to awk program here.

awk '
FNR==1{
close(outFile)
outFile=FILENAME".add"
print > (outFile)
next
}
$NF=="ADD"{
print > (outFile)
}
' *.txt

OR

awk '
FNR==1{
close(outFile)
outFile=FILENAME".add"
}
FNR==1 || $NF=="ADD"{
print > (outFile)
}
' *.txt

Explanation: Adding detailed explanation for above code.

awk '                       ##Starting awk program from here.
FNR==1{ ##Checking condition if this is first line of each file then do following.
close(outFile) ##Closing output file to avoid "too many files" error.
outFile=FILENAME".add" ##Creating variable which has output file name in it.
print > (outFile) ##Printing current line here.
next ##next will skip all further statements from here.
}
$NF=="ADD"{ ##Checking condition if last field is ADD then do following.
print > (outFile) ##Printing current line to output file.
}
' *.txt ##Passing all .txt files to awk program as an input.

excluding first and last lines from sed /START/,/END/

This should do the trick:

sed -e '/=sec1=/,/=sec2=/ { /=sec1=/b; /=sec2=/b; s/^/#/ }' < input

This matches between sec1 and sec2 inclusively and then just skips the first and last line with the b command. This leaves the desired lines between sec1 and sec2 (exclusive), and the s command adds the comment sign.

Unfortunately, you do need to repeat the regexps for matching the delimiters. As far as I know there's no better way to do this. At least you can keep the regexps clean, even though they're used twice.

This is adapted from the SED FAQ: How do I address all the lines between RE1 and RE2, excluding the lines themselves?



Related Topics



Leave a reply



Submit