This is a perfect example of why sed
is the stream editor, and will never replace the power of ex
for in-place file editing.
ex -c '/address *172.29.16.103/
?{?,/}/d
x' input
This command is a simplified form that's not as robust as it could be, but serves for illustration.
The first command finds the regex specified and moves the cursor to that line.
The second command consists of two addresses separated by a comma, upon which the d
elete command is run. ?{?
searches backwards from the current line for an open curly brace, and /}/
searches forward from the current line for a close curly brace. Everything in between is deleted (linewise, so the beginning of the open curly brace line is deleted as well).
x
saves the changes and exits. And input
is of course the name of the file.
For the input you gave, this command works exactly as desired.
Now, I mentioned this could be improved considerably. We'll start with the regex. The most obvious outness here is that periods are wildcards; the regex as given could also match "172329-16 103". So the periods must be escaped with backslashes so they will only match literal periods.
Next is the whitespace. I put two spaces followed by a * (I could have used \+
but I don't know if that feature is required in POSIX), but what if there are tabs in the file? The best solution is to use [[:space:]]
. (This would look much nicer with \+
; if anyone finds whether that is POSIX please post a comment.)
Finally, what if the regex is not found in the file? Well, then the file will simply be opened for editing, and the "search" command will fail, and an error message will be printed and the rest of the given commands won't be executed--you'll be left in the ex
editor so you can make changes by hand. However, if you want to automate the edits in a script, you probably want the editor to exit if no changes need to be made. The answer is to use the g
lobal command, and also to use the -s
flag to suppress any output from ex
:
ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d
x' input
This isn't quite equivalent to the earlier command; if there is more than one curly brace block with a matching line, the global command here will delete them all. That's probably what you want anyway.
If you want to only delete the first match, while exiting without changing the file if there are no matches at all, you can use the x
command as part of the argument to the g
command (to exit the file after the first delete command is performed) and throw in a q!
command at the bottom in case the g
command doesn't execute for lack of any matching lines.
ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d | x
q!' input
To be honest these commands make the process look much more complicated than it is; the robustness comes at the expense of extreme clarity and readability of the code. It's a trade-off.
I recommend editing a few files interactively with ex
to get a bit of a feel for it. That way you can see what you're doing. Such an editing session in ex
to do this fix interactively looks something like this:
$ ex input
"input" 23L, 843C
Entering Ex mode. Type "visual" to go to Normal mode.
:/103
host_name ServerB_172.29.16.103
:?{?,/}/d # This deletes the current block
:$p # Print and move to last line
:-5,.p # Print some more lines to check result
notification_interval 120
notification_period 24x7
}
:?}?+,.d # Trim whitespace
}
:x # Save and exit
$
The POSIX specifications for ex
provide further reading.
sed -n '/\s*address/p;' file
will solve it? Which is the same asgrep 'address' file
? Or am I missing something here? What is the output meant to look like? – Drav Sloan Sep 06 '13 at 20:28define {
to}
if that address match, It should not remove any other content, that's it – Rahul Patil Sep 06 '13 at 20:30