3
votes

I have a single long column and want to reformat it into three comma separated columns, as indicated below, using awk or any Unix tool.

Input:

Xaa
Ybb
Mdd
Tmmn
UUnx
THM
THSS
THEY
DDe

Output:

Xaa,Ybb,Mdd
Tmmn,UUnx,THM
THSS,THEY,DDe
3

3 Answers

7
votes
$ awk '{printf "%s%s",$0,NR%3?",":"\n";}' file
Xaa,Ybb,Mdd
Tmmn,UUnx,THM
THSS,THEY,DDe

How it works

For every line of input, this prints the line followed by, depending on the line number, either a comma or a newline.

The key part is this ternary statement:

NR%3?",":"\n"

This takes the line number modulo 3. If that is non-zero, then it returns a comma. If it is zero, it returns a newline character.

Handling files that end before the final line is complete

The assumes that the number of lines in the file is an integer multiple of three. If it isn't, then we probably want to assure that the last line has a newline. This can be done, as Jonathan Leffler suggests, using:

awk '{printf "%s%s",$0,NR%3?",":"\n";} END { if (NR%3 != 0) print ""}' file

If the final line is short of three columns, the above code will leave a trailing comma on the line. This may or may not be a problem. If we do not want the final comma, then use:

awk 'NR==1{printf "%s",$0; next} {printf "%s%s",(NR-1)%3?",":"\n",$0;} END {print ""}' file

Jonathan Leffler offers this slightly simpler alternative to achieve the same goal:

awk '{ printf("%s%s", pad, $1); pad = (NR%3 == 0) ? "\n" : "," } END { print "" }'

Improved portability

To support platforms which don't use \n as the line terminator, Ed Morton suggests:

awk -v OFS=, '{ printf("%s%s", pad, $1); pad = (NR%3?OFS:ORS)} END { print "" }' file
3
votes

There is a tool for this. Use pr

pr -3ats,

3 columns width, across, suppress header, comma as separator.

0
votes
xargs -n3 < file | awk -v OFS="," '{$1=$1} 1'

xargs uses echo as default action, $1=$1 forces rebuild of $0.

Using only awk I would go with this (which is similar to what proposed by @jonathan-leffler and @John1024)

{
     sep = NR == 1 ? ""   : \
          (NR-1)%3 ? ","  : \
                     "\n"
     printf sep $0
}

END {
     printf "\n"
}