Can Awk Patterns Match Multiple Lines

Can awk patterns match multiple lines?

Awk can easily detect multi-line combinations of patterns, but you need to create what is called a state machine in your code to recognize the sequence.

Consider this input:

how
second half #1
now
first half
second half #2
brown
second half #3
cow

As you have seen, it's easy to recognize a single pattern. Now, we can write an awk program that recognizes second half only when it is directly preceded by a first half line. (With a more sophisticated state machine you could detect an arbitrary sequence of patterns.)

/second half/ {
if(lastLine == "first half") {
print
}
}

{ lastLine = $0 }

If you run this you will see:

second half #2

Now, this example is absurdly simple and only barely a state machine. The interesting state lasts only for the duration of the if statement and the preceding state is implicit, depending on the value of lastLine. In a more canonical state machine you would keep an explicit state variable and transition from state-to-state depending on both the existing state and the current input. But you may not need that much control mechanism.

Matching multiple regexs on multiple lines passed as awk args

The error message match: third argument is not an array means that you are calling the match() function with three arguments, and that the third one is not an array as expected.

This is the only call to match() with three arguments:

match($0, /new[[:blank:]]+File\(/, /FileInputStream/)

Judging by the next lines, you want to match either of the two regexes. Your line should then be:

match($0, /new[[:blank:]]+File\(|FileInputStream/)

How do I match a pattern and then copy multiple lines?

Your existing awk matches correctly the rows from the ids' file, you now need to add a condition to print N lines ahead after reading the last field of the matching row. So we will set a variable p to the number of lines to print plus one (the current one), and decrease per row printing.

awk -F'/' 'NR==FNR{id[$0]; next} $1 in id{p=$6+1} p-->0{print}' file1 file2

or the same with last condition more "awkish" (by Ed Morton) and covering any possible extreme case of a huge file

awk -F'/' 'NR==FNR{id[$0]; next} $1 in id{p=$6+1} p&&p--' file1 file2

here the print condition is omitted, as it is the default action, and the condition is true again as long as decreasing p is positive.

AWK - match multiple patterns and print results in one line

Using given data below one should work, assuming there will not be any empty lines

Input

$ cat file
Current State : Active
Router1slot1# showstats
Active stats : 31
Active stats1 : 47
Router1slot1# exit
Current State : Standby
Router1slot2# showstats
Active stats : 59
Active stats1 : 56
Router1slot2# exit

Output

$ awk -F'[#:]' -v OFS=, '/exit/{print r,s; r=s=""; next}/showstats/{r=$1;next}{s=(s?s OFS:"")$2}' file
Router1slot1, Active, 31, 47
Router1slot2, Standby, 59, 56

Explanation

awk -F'[#:]' -v OFS=, '             # call awk set and input and ouptut field sep
/exit/{ # if exit word found in record
print r,s; # print variable r, and s
r=s=""; # set variable r and s to null
next # stop processing go to next line
}
/showstats/{ # if showstats found
r=$1; # copy first column to variable r
next # stop processing go to next line
}
{
s=(s?s OFS:"")$2 # variable s contains 2nd field of each line
# (which is not skipped above using next),
# if s was set before then concatenate
# s with current record 2nd field,
# where separator being OFS between
# them (OFS=output field separator)
}' file

Multiline pattern matching in bash

This awk can do the job:

awk -v s='Submitted' '$1 != s{if(p != "") print p; p=$2} $1 == s{p=""}' file

SCRIPT100
SCRIPT10000
SCRIPT10001

Reference: Effective AWK Programming

How do I match two following lines using awk?

If you want to match a block of two lines, you can use a "flag" variable that is set whenever the first line of the block gets matched.

awk '
1
/nginx/{flag=1;next}
flag==1 && / env_file:/{flag=0;print " - ../env/nginx.env"}
flag=0
' filename

Multiple awk pattern matching in one line

awk works on method of regexp then action in this if we are mentioning /..../ and not mentioning any action so when condition is TRUE then by default print of line will happen. In case you want to put this into 2 different statements try like:

awk '/foo/;/bar/'  Input_file

Above will mean like:

  1. Since they are segregated with ; these will be treated as 2 different conditions.
  2. When /foo/ is true for any line then NO action is mentioned so print of that line will happen.
  3. When /bar/ is true for any line same thing for this also, condition is true and no action mentioned so print of line will happen.

But point to be noted that in case any line has both strings in it so that line will be printed 2 times, which I believe you may NOT want it so you could do like following:

OR within single condition itself try something like:

awk '/foo|bar/'  Input_file

Or in case you need to check if strings present in same line then try Like:

awk '/foo/ && /bar/'  Input_file

Matching regex of multiple lines in AWK. && operator?

[Update based on clarification.]

One high order bit is that Awk is a line-oriented language, so you won't actually be able to do a normal pattern match to span lines. The usual way to do something like this is to match each line separately, and have a later clause / statement figure out if all the right pieces have been matched.

What I'm doing here is looking for an a in the second field on one line, a b in the second field on another line, and a c in the second field on a third line. In the first two cases, I stash away the contents of the line as well as what line number it occurred on. When the third line is matched and we haven't yet found the whole sequence, I go back and check to see if the other two lines are present and with acceptable line numbers. If all's good, I print out the buffered previous lines and set a flag indicating that everything else should print.

Here's the script:

$2 == "a" { a = $0; aLine = NR; }
$2 == "b" { b = $0; bLine = NR; }
$2 == "c" && !keepPrinting {
if ((bLine == (NR - 1)) && (aLine == (NR - 2))) {
print a;
print b;
keepPrinting = 1;
}
}
keepPrinting { print; }

And here's a file I tested it with:

JUNK UP HERE NOT STARTING WITH NUMBER
1 a 0.110 0.069
2 a 0.062 0.088
3 a 0.062 0.121
4 b 0.062 0.121
5 c 0.032 0.100
6 d 0.032 0.100
7 e 0.032 0.100
8 a 0.099 0.121
9 b 0.098 0.121
10 c 0.097 0.100
11 x 0.000 0.200

Here's what I get when I run it:

$ awk -f blort.awk blort.txt
3 a 0.062 0.121
4 b 0.062 0.121
5 c 0.032 0.100
6 d 0.032 0.100
7 e 0.032 0.100
8 a 0.099 0.121
9 b 0.098 0.121
10 c 0.097 0.100
11 x 0.000 0.200


Related Topics



Leave a reply



Submit