Reputation: 1545
I need to use sed
to replace every matching two-line pattern with a three line pattern. Here's my input file (tempfile.txt
).
lease 192.168.6.100 {
binding state free;
hardware ethernet 00:e0:4c:68:00:96;
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
lease 192.168.6.100 {
binding state free;
hardware ethernet 00:e0:4c:68:00:96;
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
Basically, if a client-hostname "HOSTNAME";
is missing, then it should be replaced with a tab
and then a newline
.
My attempt:
sed 'N; /hardware.*}/d; P; D' tempfile.txt
The result is:
lease 192.168.6.100 {
binding state free;
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
lease 192.168.6.100 {
binding state free;
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
This is my desired output.
lease 192.168.6.100 {
binding state free;
hardware ethernet 00:e0:4c:68:00:96;
<tab>
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
lease 192.168.6.100 {
binding state free;
hardware ethernet 00:e0:4c:68:00:96;
<tab>
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
So as you can see, there are consistently three lines between the curlies. That's what I'm aiming for.
Upvotes: 0
Views: 101
Reputation: 52181
This does the trick (piping to cat -A
to show non-printable characters):
$ sed -r 'N;s/^([[:space:]]*hardware.*)(\n})$/\1\n\t\2/;t;P;D' infile | cat -A
lease 192.168.6.100 {$
binding state free;$
hardware ethernet 00:e0:4c:68:00:96;$
^I$
}$
lease 192.168.6.100 {$
binding state active;$
hardware ethernet 00:e0:4c:68:00:96;$
client-hostname "andrew-H81M-S2PH";$
}$
lease 192.168.6.100 {$
binding state free;$
hardware ethernet 00:e0:4c:68:00:96;$
^I$
}$
lease 192.168.6.100 {$
binding state active;$
hardware ethernet 00:e0:4c:68:00:96;$
client-hostname "andrew-H81M-S2PH";$
}$
Instead of deleting matches, this captures the two lines supposed to surround the empty line and replaces with the newline and tab between. I've also added a few anchors for safer matching.
There is a bit of trickery involved because the pattern space contains two newlines after a substitution, but P;D
prints only the first line and the starts a new cycle, which leads to unwanted newlines also after lines containing client-hostname
.
Explained in more detail:
N # Append next line to pattern space
# If the hostname is missing, insert a newline and a tab
s/^([[:space:]]*hardware.*)(\n})$/\1\n\t\2/
t # If we did the substitution, jump to end (prints complete pattern space)
P # Print first line in pattern space
D # Delete first line in pattern space - starts new cycle
Upvotes: 2
Reputation: 15214
I took the liberty to add another curly ...
sed 'N; s/hardware.*}/\t\n}/; P; D' andy
lease 192.168.6.100 {
binding state free;
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
lease 192.168.6.100 {
binding state free;
}
lease 192.168.6.100 {
binding state active;
hardware ethernet 00:e0:4c:68:00:96;
client-hostname "andrew-H81M-S2PH";
}
Upvotes: 1