Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to align the selected portion of a text file at 9 bytes each column.

For example suppose my text file looks like below.

00 2f c6 b8 29 fd 02 37 11  00 9f 74 34 0b 60 72 38 20  00 9e 61 33 8e ab 8a c0 09 
00 fa f0 66 6d 0c 44 d6 24 00 a1 11 9d a2 13 a5 b3 83 

I want the resulting file to be like

00 2f c6 b8 29 fd 02 37 11 
00 9f 74 34 0b 60 72 38 20 
00 9e 61 33 8e ab 8a c0 09 
00 fa f0 66 6d 0c 44 d6 24 
00 a1 11 9d a2 13 a5 b3 83 

What is the easiest way to do this? Is it possible to do it in bash using sed or awk maybe?

Or a better way to frame the question will be I have formatted my input sequence as seen below.

00 88 ec 40 bf 94 1d 63
f4 00 04 1c 4e 06 d0 2c
2e f9 00 90 03 51 d5 71
cc 86 79 00 24 6b 22 30
b6 66 0f 5f 00 c1 cd a5
c8 45 b9 88 85 00 c0 de
ae 47 d9 91 f9 d3 00 5b

That is 8 bytes each line.If you notice carefully in line 1 first byte is 00.in line 2 the second byte is 00 and in line 3 the third byte is 00.I want the align the whole file so that the all the lines begin with a 00.hope this helps

share|improve this question
1  
P.S. To format your code so it looks pretty, highlight the code and press CTRL+K or click on the icon that looks like a { } –  SiegeX Jan 25 '12 at 22:34

4 Answers 4

up vote 5 down vote accepted

This will work regardless of how many bytes are on a single line

sed ':a $!N;s/\n/ /;ta;s/\(\(\([[:xdigit:]]\)\{2\} *\)\{8\}\([[:xdigit:]]\)\{2\}\) */\1\n/g'

Input

$ cat alignbyte
00 2f c6
b8 29 fd 02
37 11 00 9f 74 34 0b 60 72 38
20 00 9e 61 33 8e ab 8a c0 09
00 fa f0 66
6d 0c 44 d6 24
00 a1 11 9d a2 13 a5 b3 83

Output

$ sed ':a $!N;s/\n/ /;ta;s/\(\(\([[:xdigit:]]\)\{2\} *\)\{8\}\([[:xdigit:]]\)\{2\}\) */\1\n/g' alignbyte
00 2f c6 b8 29 fd 02 37 11
00 9f 74 34 0b 60 72 38 20
00 9e 61 33 8e ab 8a c0 09
00 fa f0 66 6d 0c 44 d6 24
00 a1 11 9d a2 13 a5 b3 83

I just noticed that your input file seems to have two blank spaces after each set of 9 bytes, except for the very last set. If that is a typo and all sets of 9 bytes are indeed separated by two spaces then the command to get what you want is simply this:

sed 's/  /\n/g' file
share|improve this answer
    
Like the other answer, this won't work if the input has a line with n%9 != 0 bytes. –  Kevin Jan 25 '12 at 22:03
    
that is true.I have formatted my output to be 8 bytes long in each line and this sed expression does not work. –  liv2hak Jan 25 '12 at 22:05
    
@liv2hak see updated answer which is byte-per-line agnostic –  SiegeX Jan 25 '12 at 22:16

One approach that doesn't care about the exact shape of the input is to split it into one item per line then group items in the desired number.

tr -s '[:space:]' '\n' |
awk '
    NR % 9 != 1 {printf " "}
    {printf "%s", $0}
    NR % 9 == 0 {print ""}
    END {if (NR % 9) print ""}'

If you don't mind an extra space at the end of the line, you can simplify the awk code a bit:

tr -s '[:space:]' '\n' |
awk '
    {printf "%s ", $0}
    NR % 9 == 0 {print ""}
    END {if (NR % 9) print ""}'

If your input has no blank lines and all items are the same width, then there's a simpler solution: put everything on one line then perform line folding.

{ tr -s '\n' ' '; echo; } | fold -w 27

If you have the fmt utility, it can combine both subtasks:

fmt -w 27
share|improve this answer
    
Interesting: tr -s ... Translation occurs before the Squeeze... very handy –  Peter.O Jan 26 '12 at 3:26

A basic trick:

grep -o ".. .. .. .. .. .. .. .. .." your-file.txt

If the lines length may not be multiple of 9 hexa bytes, then remove the CRCL:

tr -d '\n\r' < your-file.txt | grep -o ".. .. .. .. .. .. .. .. .."

If the file may contain consecutive spaces:

tr -s ' \n\r' ' ' < your-file.txt | grep -o ".. .. .. .. .. .. .. .. .."

I am appreciate the complex sed/awk programming answers.
Here, I propose readable tricks using basic tools.

share|improve this answer
3  
This will only work if each line of the input has a multiple of nine bytes. –  Kevin Jan 25 '12 at 21:35
1  
that is true.in case of my file that is not true.is there a better way to do that.? –  liv2hak Jan 25 '12 at 21:50
    
Dear @Kevin, I have just added tr to clean up the input file –  olibre Jan 26 '12 at 9:05
    
Dear @liv2hak I have just added tr to clean up the input file –  olibre Jan 26 '12 at 9:06

This might work you (in the second instance where each line is 8 bytes long):

 sed '$!N;s/\n/ /;s/ /\n/9;P;D' file

In the first instance (variable length records):

fmt -w27 file

Or with GNU sed:

sed 'L27;d' file
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.