7

I have some data where the 4th column will either be frz or -. I would like to find all lines where the 4th column is frz only if the 4th column on the next line is - and then print both lines.

Sample input:

2018-04-09T14:15:23.366Z  7 multi -   uuid1 uuid2 uuid3 -
2018-04-09T14:15:23.978Z  8 multi frz   uuid1 uuid3 -        -
2018-04-09T14:29:35.826Z  8 multi frz   uuid1 uuid3 uuid2 -
2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
2018-06-28T00:35:54.338Z  9 multi -   uuid1 uuid2 -        -
2018-06-28T00:47:51.679Z  9 multi -   uuid1 uuid2 uuid3 -
2018-06-28T00:47:51.720Z 10 multi -   uuid1 uuid3 -        -
2018-06-28T00:47:58.863Z 10 multi -   uuid1 uuid3 uuid2 -
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -

Expected output:

2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -

I've found a few awk commands to print the line after a match but I can't figure out how to match both lines and print both.

What I currently have:

$ awk 'f{print;f=0} $4=="frz"{f=1}' input
2018-04-09T14:29:35.826Z  8 multi frz   uuid1 uuid3 uuid2 -
2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -
5

How about:

awk '$4=="-" && prev4=="frz" {print prevline; print} {prev4 = $4; prevline=$0}' file
  • ty sir, exactly what I need! – Jesse_b Jun 28 '18 at 17:35
4

If you have GNU grep and your pattern doesn't occur elsewhere in the data, you can try this :

grep -A1 frz | grep -vB1 frz

Explanation

The first grep captures all lines where the pattern occurs, plus the next one :

-A NUM, --after-context=NUM Print NUM lines of trailing context after matching lines. Places a line containing a group separator (--) between contiguous groups of matches.

The output of this first command on your sample input is :

2018-04-09T14:15:23.978Z  8 multi frz   uuid1 uuid3 -        -
2018-04-09T14:29:35.826Z  8 multi frz   uuid1 uuid3 uuid2 -
2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
--
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -

Then the second command searches for lines not containing the pattern, and prints them with the line before :

-B NUM, --before-context=NUM Print NUM lines of leading context before matching lines. Places a line containing a group separator (--) between contiguous groups of matches.

As noted in the grep man page, the ouput contains group separators (--) :

2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
--
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -

You can add a third grep to remove them if needed :

grep -A1 frz | grep -vB1 frz | grep -v '^--$'
  • 1
    Nice. The regular expressions can be made such that "frz" is taken in the 4th column, but the bones of the solution are strong. – glenn jackman Jun 28 '18 at 20:50
3

I'd like to offer a completely impractical GNU grep approach. Works, but looks nasty.

grep -Pzo "^\S+\s+\S+\s+\S+\s+frz\s+.*\n\S+\s+\S+\s\S+\s+\-\s+.*" input

Example.

$ cat file
2018-04-09T14:15:23.366Z  7 multi -   uuid1 uuid2 uuid3 -
2018-04-09T14:15:23.978Z  8 multi frz   uuid1 uuid3 -        -
2018-04-09T14:29:35.826Z  8 multi frz   uuid1 uuid3 uuid2 -
2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
2018-06-28T00:35:54.338Z  9 multi -   uuid1 uuid2 -        -
2018-06-28T00:47:51.679Z  9 multi -   uuid1 uuid2 uuid3 -
2018-06-28T00:47:51.720Z 10 multi -   uuid1 uuid3 -        -
2018-06-28T00:47:58.863Z 10 multi -   uuid1 uuid3 uuid2 -
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -
$ grep -Pzo "^\S+\s+\S+\s+\S+\s+frz\s+.*\n\S+\s+\S+\s\S+\s+\-\s+.*" file
2018-04-09T17:19:01.901Z  8 multi frz uuid1 uuid3 uuid2 -
2018-06-03T22:12:38.688Z  8 multi -   uuid1 uuid3 uuid2 -
2018-06-28T16:29:01.624Z 10 multi frz uuid1 uuid3 uuid2 -
2018-06-28T17:29:01.624Z 10 multi - uuid1 uuid3 uuid2 -
$ grep -V 2>&1|head -1
grep (GNU grep) 2.20
$
  • I get grep: unescaped ^ or $ not supported with -Pz with this. grep version "grep (GNU grep) 2.25" -- I think you need to replace ^ with \n – glenn jackman Jun 28 '18 at 19:02
  • Interesting. v2.20 here, which doesn't have that trouble. Replacing ^ with \n no good on v2.20, results in an unwanted empty line prior to each match. – steve Jun 28 '18 at 21:36
  • 1
    I can see on the NEWS file in the grep git repo that they were changing things related to this in versions 2.24 and 2.25 – glenn jackman Jun 28 '18 at 21:54
1

You can try this sed too

sed -E '
  /([^ ]* *){3}frz .*/!d
  $!N
  /(.*\n)([^ ]* *){3}- .*/!D
' infile
  • Constrain the N to operate on not last lines, $!N OTW, a last line ending with "frz" in it's 3rd field would get printed too. – Rakesh Sharma Jun 29 '18 at 16:37
  • @RakeshSharma You are right thanks update the answer – ctac_ Jun 29 '18 at 16:54
  • The first regex is in need of an overhaul, for as things stand now, it will match a line with "frz" in 4th field when it doesn't find in the 3rd but in 4th. You need to ⚓ it to the beginning of pattern space. The .* is superfluous in both the regexes. – Rakesh Sharma Jun 29 '18 at 17:46
  • @RakeshSharma Sorry but I don't understand exactly what you want to say. Yes my answer is not perfect and it's always imaginable to find a way where it fail. If you have a better solution, you can post a answer. – ctac_ Jun 29 '18 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.