1

I have found a similar topic but could not figure out how to implement it for my own use:

grab multiple lines after a matching target line

Here's the issue:

I'm trying to implement it on a project of my own but can't seem to make it work. I am using Linux, can someone break it down?

Basically what I'm trying to do is go through a log bundle and capture specific lines along with their stack\details. Here's an example:

2020-01-20T05:58:19.119Z verbose vpxa[6E21B70] [Originator@6876 sub=PropertyProvider opID=k5cokp1a-928316-auto-jwal-h5:70047736-92-01-84] [CommitChangesAndNotify] Updating cached values
2020-01-20T05:58:19.119Z info vpxa[6E21B70] [Originator@6876 sub=Default opID=k5cokp1a-928316-auto-jwal-h5:70047736-92-01-84] [VpxLRO] -- ERROR task-107599 -- **vm-1178** -- vim.VirtualMachine.reconfigure: vmodl.fault.InvalidArgument:
--> Result:
--> (vmodl.fault.InvalidArgument) {
-->    faultCause = (vmodl.MethodFault) null,
-->    faultMessage = (vmodl.LocalizableMessage) [
-->       (vmodl.LocalizableMessage) {
-->          key = "msg.disk.extendFailure",
-->          arg = (vmodl.KeyAnyValue) [
-->             (vmodl.KeyAnyValue) {

I'll want to capture every line that contains "vm-1178" and all subsequent lines that start with "-->" until the pattern changes, then start looking for vm-1178 until the next time this occurs, etc.

Hope it makes sense. Thanks!

2
  • Hi Eitan, what do you mean with "until the pattern changes"? Describe it better, put that pattern change in your input file and then the expected output. Commented Apr 14, 2020 at 11:12
  • Do I assume correctly that you mean you want to print all lines containing "vm-1178", and all lines after such a line that start with -->? Commented Apr 14, 2020 at 11:17

3 Answers 3

6

Try this,

awk '!/^-->/{p=0} /vm-1178/{p=1} p'
  • !/^-->/{p=0}: Set var p (like print) to 0 whenever line not begins with -->.
  • /vm-1178/{p=1}: Set var p = 1 whenever line matches /vm-1178/.
  • p: Print the line whenever p is true (here=1)
5
  • Wow, I completely missed your answer. I guess I can delete mine. It may still be worth using index instead of the / ... / match in case the OP ever wants to look for a pattern with special characters in it. Commented Apr 14, 2020 at 11:31
  • I posted mine after yours, but I could save some characters ;-) Commented Apr 14, 2020 at 11:33
  • Ok, I was already doubting my eyes there ;). Still, yours is more compact than mine. Commented Apr 14, 2020 at 11:34
  • That works! I'm just curious how, because to my understanding the !/^-->/{p=0} part means that we don't print those lines, so how come it becomes true after it has found the vm-1178 string? Commented Apr 19, 2020 at 13:00
  • When a line appears with vm-1178, all three parts will run. The first part sets p to 0, but the second part sets it back to 1 right away, the last part prints the line becaue p is 1. Commented Apr 19, 2020 at 13:05
3

You could use awk for that purpose:

awk 'index($0,"vm-1178")>0 {in_pat=1; print; next} \
in_pat == 1 && $0 ~ /^-->/ {print; next} \
{in_pat=0}' logfile.txt

It contains three rules:

  • The first rule will look for lines containing the pattern and print these, as well as setting an internal flag in_pat to 1.
  • The second rule states that all subsequent lines starting with --> will be printed as well.
  • The third rule is used to reset that flag upon the very first line not containing the pattern or not starting with a -->, so that nothing is printed until the pattern is found again.

Note that in the first rule, the index function is used rather than a RegExp match. This is so that you can also look for patterns containing characters that have a special meaning in regular expressions.

2
  • Amazing. So while waiting for you guys to answer I decided to create a C# program that does exactly what I needed here, and your script is three times faster than the program. Thanks a bunch! Commented Apr 19, 2020 at 13:04
  • Wow, that surprises me, too (although I guess awk has been around so long that it got streamlined a lot). Anyways, it was a nice question to solve, I don't understand why it got downvotes ... Commented Apr 20, 2020 at 6:57
-1

Using perl, this would work:

 perl -ne ' { $t=0 if ( !/^-->/ ); $t=1 if(/vm-1178/); print if($t); }' <filename>
7
  • 1
    I think you have a typo in your matching expression (missing the -). Also, if I try this with a log file that also contains lines without the pattern and not starting with -->, it prints the entire content. Could you be mistaking the use of character lists/classes [ ... ] here? Commented Apr 14, 2020 at 11:37
  • @AdminBee : Yeah got it...i believe the edited answer will work.And just why down vote it :( Commented Apr 14, 2020 at 11:40
  • I didn't, so I can't tell ... Commented Apr 14, 2020 at 11:42
  • I did, because it doesn't work. Character classes are not the way to go here. ^[^-->] matches lines not starting with - or > instead of -->, e.g. empty lines or --<< do not print this line. Commented Apr 14, 2020 at 12:13
  • @pLumo : The above works , now remove the vote pls :) Commented Apr 14, 2020 at 12:26

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.