yaserso
yaserso

Reputation: 2868

How to grep a block of text?

I want to delete a block of specific server from this file

NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock
</VirtualHost>
<VirtualHost *>
DocumentRoot "documentroot"
ServerName newserver
</VirtualHost>

So far I've used the following, but it doesn't seem to give me the proper result, but instead greps for each line of the block (of the inner grep) individually.

grep -vF "$(grep -w -B 2 -A 1 'newserver'/Applications/MAMP/conf/apache/httpd.conf)" /Applications/MAMP/conf/apache/httpd.conf;

The above results in the following:

NameVirtualHost *
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock

While instead I want the following:

NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock
</VirtualHost>

Upvotes: 0

Views: 3416

Answers (4)

st0ne
st0ne

Reputation: 4265

Another one with diff and parts of your initial command:

diff  <(grep -w -B 2 -A 1 'newserver' /Applications/MAMP/conf/apache/httpd.conf) \
      /Applications/MAMP/conf/apache/httpd.conf  | 
grep -e '^> ' | sed -e 's/^> //'

Upvotes: 2

αғsнιη
αғsнιη

Reputation: 2761

awk alone:

$ awk '!/ServerName newserver/{printf "%s%s", $0, RS}' RS='</VirtualHost>' file

NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock
</VirtualHost>

RS defines </VirtualHost> as record separator and awk will prints those records($0) that doesn't match with ServerName newserver in it. And then print the RS(</VirtualHost>) again which is removed when we change RS to that.

Upvotes: 2

anubhava
anubhava

Reputation: 785621

If you want to delete an entry with ServerName newserver then use this perl one-liner:

perl -0pe 's~(?s)\s?<VirtualHost[^>]*>((?!</VirtualHost>).)*ServerName newserver.*</VirtualHost>~~' file
NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock
</VirtualHost>

Using a variable:

s='newserver'
perl -0pe 's~(?s)\s?<VirtualHost[^>]*>((?!</VirtualHost>).)*ServerName '"$s"'.*</VirtualHost>~~' file

RegEx Demo

Explanation:

This perl command uses a regex that matches a block starting from these 2 tags:

<VirtualHost[^>]*>

and

</VirtualHost>

and finds this pattern in between these 2 patterns:

ServerName newserver

It uses a negative lookahead pattern using (?!</VirtualHost>) that makes sure only when ServerName test comes then only match is found.

Upvotes: 1

Gilles Qu&#233;not
Gilles Qu&#233;not

Reputation: 185550

$ tac vhost | awk 'NR>4' | tac
NameVirtualHost *
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs"
ServerName localhost
</VirtualHost>
<VirtualHost *>
DocumentRoot "/Applications/MAMP/htdocs/bedrock/web"
ServerName bedrock
</VirtualHost>

This is a 'trick' to remove the last Vhost by the known numbers of lines it contains

Upvotes: 1

Related Questions