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:
- Since they are segregated with
;
these will be treated as 2 different conditions. - When
/foo/
is true for any line then NO action is mentioned so print of that line will happen. - 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
How to Ensure Only One Instance of a Bash Script Is Running
How to Compile a 32-Bit Binary on a 64-Bit Linux Machine With Gcc/Cmake
How to Remove ^[, and All of the Escape Sequences in a File Using Linux Shell Scripting
Bash Script Process Substitution Syntax Error: "(" Unexpected
The Difference Between Fork(), Vfork(), Exec() and Clone()
Redirect Stderr/Stdout of a Process After It's Been Started, Using Command Line
Linux: Copy and Create Destination Dir If It Does Not Exist
How to Redirect the Output of the Time Command to a File in Linux
Use of Floating Point in the Linux Kernel
How to Setup Public-Key Authentication
Setting Environment Variables in Linux Using Bash
What Are the Return Values of System Calls in Assembly
How to Redirect Output of Systemd Service to a File
How to Manage Perl Modules When Using a Package Manager
Maximum Length of Command Line Argument That Can Be Passed to Sql*Plus