How to print values in a text file to columnated file using shell script

I have an output.txt from running a shell script as follows:

abc.txt
errorstatus1
Fri Nov 11 02:00:09 2016
def.txt
errorstatus2.txt
Sat Nov 12 03:00:09 2016

The text file has multiple entries line by line in the same manner. I want to print these values into columns: Filename,Status and Timestamp as follows:

Filename      Status        Timestamp
abc.txt     errorstatus1   Fri Nov 11 02:00:09 2016
def.txt     errorstatus2   Sat Nov 12 03:00:09 2016

With paste:

paste - - - <file.txt

this will output the newline separated file content as columns, and three tab separated columns per line.

Adding the header:

echo Filename Status Timestamp; paste - - - <file.txt

To columnize the output, take help from column:

{ echo Filename Status Timestamp; paste - - - <file.txt ;} | column -t

Example:

% cat file.txt
abc.txt
errorstatus1
Fri Nov 11 02:00:09 2016
def.txt
errorstatus2.txt
Sat Nov 12 03:00:09 2016

% { echo Filename Status Timestamp; paste - - - <file.txt ;} | column -t
Filename  Status            Timestamp
abc.txt   errorstatus1      Fri        Nov  11  02:00:09  2016
def.txt   errorstatus2.txt  Sat        Nov  12  03:00:09  2016

You could use awk:

awk 'NR % 3 {printf "%s ", $0; next}1'

Output might not be as pretty:

$ awk 'NR % 3 {printf "%s ", $0; next} 1' input
abc.txt errorstatus1 Fri Nov 11 02:00:09 2016
def.txt errorstatus2.txt Sat Nov 12 03:00:09 2016

You could use %s\t instead for tab-separated output.

  • NR % 3 is zero (and false) for every third line, so the other lines are printed with a space after them instead of a newline. next just starts the next iteration.
  • Every third line is printed as-is because of the final 1, with a newline after it, since it doesn't match the first block.

There's also rs (BSD reshape utility):

DESCRIPTION
     rs reads the standard input, interpreting each line as a row of blank-
     separated entries in an array, transforms the array according to the
     options, and writes it on the standard output.  With no arguments it
     transforms stream input into a columnar format convenient for terminal
     viewing.

In particular,

     -e      Consider each line of input as an array entry.

So

$ rs -e < file
abc.txt                   errorstatus1              Fri Nov 11 02:00:09 2016
def.txt                   errorstatus2.txt          Sat Nov 12 03:00:09 2016

or (to add the header)

$ { printf '%s\n' Filename Status Timestamp ; cat file ; } | rs -e
Filename                  Status                    Timestamp
abc.txt                   errorstatus1              Fri Nov 11 02:00:09 2016
def.txt                   errorstatus2.txt          Sat Nov 12 03:00:09 2016

For completeness, you can do this with sed too:

sed -e '1iFilename\tStatus\tTimestamp' -e 'N;N;y/\n/\t/' file.txt
  • 1iFilename\tStatus\tTimestamp inserts the header line before line 1
  • N;N reads two more lines into the pattern buffer, giving a total of 3 newline separated lines
  • y/\n/\t/ replaces all newlines with tabs in the pattern buffer

The i, N and y sed commands are documented here.