0

I have this kind of text file that I want to parse:

Host server1
     option1 value1
     option2 value2
     option3 value3
     ...
Host server2
     option1 value1
     option2 value2
     option3 value3
     ...
Host server3
     option1 value1
...

The goal is when I provide the name to the input, for example server2, it should return:

Host server2
     option1 value1
     option2 value2
     option3 value3
     ...

Then I tried to write the below regex and tested it on an online regex playground, it works as expected.

/((Host server2\n)(^ +.+\n*)+)/gm

But then I have no clue on how to apply this regex to some linux tools like grep, sed, perl or awk. I have tried grep but it won't apply on multiline search. It does by using -z flag but then it still won't make the regex work (tried using -Pzo, didn't work). And I'm not that familiar with perl or awk (for regex use).

So my current solution is using sed -n '/foo/,/bar/p' input_file:

string="server1"

search=$(cat input_file | grep Host | grep -w -A1 "$string")
foo=$(head -1 <<< "$search")
bar=$(tail -1 <<< "$search")

sed -n "/$foo/,/$bar/p" input_file | head -n -1

This works as expected but I want to see the regex approach. And one more thing, I don't want to install any additional tools.

3
  • cat data | grep -oPz "(?s)server2.*?\Host" Does this help I can work on it some more but this will return all text from "server2" till the next appearance of "Host". It won't work for server3 because there is not "Host" at the end but it illustrates lookahead so it should help. – Jason Croyle Mar 7 at 2:52
  • cat data | awk '/server2/{flag=1;next}/Host/{flag=0}flag' This is the awk version of basically the same command it will print every line after "server2" till the next occurrence of "Host" – Jason Croyle Mar 7 at 2:59
  • @JasonCroyle that would be the same approach as the sed's but it will successfully return a correct value for server3. As sed -n '/foo/,//p' file will print from foo until the end of the file. – annahri Mar 7 at 17:29
1

You were almost there. A minor detail that grep regexes don't like sitting inside slashes /.../

  • One more thing we turn on the multiline matching mode (?m) whereby we can use the caret ^ to symbolize beginning of line (the position to the right of a newline) as also the very beginning of the string , which can also be accessed via \A.
  • grep outputs the chunks it grepped suffixed by a NULL so we need to rake it away.
  • Rest is all your stuff so you anyway know how your regex is matching.

grep -Pzo '(?m)((^Host server2\n)( +.+\n*)+)' file | tr -d '\0'
1
  • This is awesome! Are there any references about turning on/off a matching mode for grep? – annahri Mar 7 at 17:25

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.