barefly
barefly

Reputation: 378

awk - Printing output in 3 column format

I have a text file of data that appears in the following format.

apropos c
awk nc
chsh c
date nc
grep nc
i3 nc
ip6tables nc

I am trying to filter this data through awk, to produce a 3 column format, similar to below.

apropos          awk          chsh
date             grep         i3

I do not need the second column of information on the file, but would like a clean and aligned output of the first column. I found the following code elsewhere, and modified it a bit to only output the first column of data. Problem is that it comes out misaligned due to the usage of tabs.

awk '{printf (NR %3 == 0 )? $1 "\n" : $1"\t\t" }'

Doing a bit more research I found the usage of width via awk's printf (ie. "%-10s"). Only problem is I am not quite sure how to integrate it into my command to get it to do what I'd like. Any help would be appreciated, thanks!

Upvotes: 2

Views: 3395

Answers (3)

Ed Morton
Ed Morton

Reputation: 203209

This might be more useful to you than hard-coding some arbitrary field width like 10:

$ awk '{ORS=(NR%3?FS:RS); print $1}' file | column -t
apropos    awk   chsh
date       grep  i3
ip6tables

or if you do want to drop ip6tables from the output as shown in your sample input/output:

$ awk '{rec = rec OFS $1} !(NR%3){print rec; rec=""}' file | column -t
apropos  awk   chsh
date     grep  i3

If you don't pipe to column and don't want to pick some arbitrary number as the field width then you need awk to make 2 passes of the input file to figure out the max width of each column first before printing (see https://stackoverflow.com/a/38791539/1745001).

wrt the first example - running any UNIX tool on input that does not end in a newline is relying on undefined behavior per the POSIX spec so if your column gives a warning when there's a missing newline after ip6tables then add it:

$ awk '{ORS=(NR%3?FS:RS); print $1} END{if (NR%3) printf "%s", RS}' file | column -t
apropos    awk   chsh
date       grep  i3
ip6tables

Upvotes: 4

hek2mgl
hek2mgl

Reputation: 157947

You can use the following awk | column pipe:

awk '{sep=NR%3?OFS:ORS;printf "%s%s", $1, sep}END{if(NR%3)print ""}' a.txt  \
  | column  -t

Note: Since (at least) the BSD version of the column command will print a warning:

column: line too long

and omit the last line in case the number of lines in the list is not a multiple of the column count you need to print a newline after the last element in that case.

Upvotes: 1

karakfa
karakfa

Reputation: 67467

a non-awk solution

$ cut -d' ' -f1 <file | paste - - - | column -t

apropos    awk   chsh
date       grep  i3
ip6tables

or with pr

$ cut -d' ' -f1 <file | pr -3at

apropos                 awk                     chsh
date                    grep                    i3
ip6tables

Upvotes: 1

Related Questions