I am tailing a log file and want to make it more readable.
The current output is something like this:
HH:MM:SS.ss CONTROL:00011100001110101010111000000000 HH:MM:SS.ss INDICATION:00000001110101001111010101011011
I want the output to be more like this:
HH:MM:SS.ss CONTROL:00011100 00111010 10101110 00000000 HH:MM:SS.ss INDICATION:00000001 11010100 11110101 01011011
It would be great if sed
could be used to insert the spaces.
The spaces need to be every 8 characters — it will always be in binary data after the last :
in octets (but the octets are missing the spaces I want to see).
Advertisement
Answer
This code works with both GNU and BSD (macOS) versions of sed
:
sed -e ':a' -e 's/^(.*:([01]{8} )*)([01]{8})([^ ])/13 4/' -e 't a'
Given the data file:
HH:MM:SS.ss CONTROL:00011100001110101010111000000000 HH:MM:SS.ss INDICATION:00000001110101001111010101011011 17:49:23.96 MODIFIED:0100010010101010101101010101010101001010101010111110100010011101
it gives the output:
HH:MM:SS.ss CONTROL:00011100 00111010 10101110 00000000 HH:MM:SS.ss INDICATION:00000001 11010100 11110101 01011011 17:49:23.96 MODIFIED:01000100 10101010 10110101 01010101 01001010 10101011 11101000 10011101
The first -e
command creates a label a
; the third jumps to the label a
if the commands in between made a substitution (it’s a loop in sed
). The fun is all in the middle command:
s/^(.*:([01]{8} )*)([01]{8})([^ ])/13 4/
The (…)
notation captures information that can be referred to with n
in the replacement clause. They can nest, too. The {8}
requires 8 (in this case) of the previous unit. The previous unit is [01]
, the binary digits.
Overall, it captures everything up to the last colon :
plus 0 or more units of 8 binary digits followed by a blank (and captures all this as 1
; there’s also a 2
in there, but I don’t use it), plus one unit of 8 binary digits (captured as 3
) followed by a non-blank (captured as 4
). It replaces them with 13 4
.
Because the 4
needs to be part of the next sequence of 8 binary digits, you need the looping rather than a g
modifier on the substitute command.
FWIW: I wrote the code in a file sed.script
containing:
:a s/^(.*:([01]{8} )*)([01]{8})([^ ])/13 4/ t a
and then ran:
sed -f sed.script data
That can sometimes be a useful technique. Here, it’s not critical, but it can simplify life, especially if you need to process quotes — single, double, back quotes — in the sed script. The file is not affected by the shell interpreting the contents of the regexes.