reformat short per-line data into a(n indexed) tabular layout to fill my terminal

38 Views Asked by At

I have a text file containing a small piece of data on each line: Maybe it's a word, or a single number. For simplicity let's assume there are no empty lines and no headers within that file. For example, suppose my input is:

hobby
anger
experienced
profession
golf
director
code
telephone

Now, I want to have that input laid out on my terminal in a tabular form, row-major, preserving order. Suppose my terminal is 40 chars wide; this could be:

hobby      anger     experienced
profession golf      director
code       telephone

(but I'm also ok with the columns all having the same width.)

A concise way of doing that without a long shell script would already be nice. Beyond this, I would also like to have indices, like so:

   0          1         2
0  hobby      anger     experienced
3  profession golf      director
6  code       telephone

This is doable with nl --line-increment, but the thing is, I would need to know the number of columns before I know what the maximum index is, and I need the maximum index to know what the index column width is, and I need to know the index column width to decide how many columns can fit in a row, so we have a bit of a viciuous cycle.


What I have so far:

If I forego any aligment, as well as auto-maximization of number of columns per line, I can use:

per_line=3;  pr -a -${per_line} -t -s\  | nl -v 0 --line-increment ${per_line}

to get:

     0  hobby anger experienced
     3  profession golf director
     6  code telephone
3

There are 3 best solutions below

3
einpoklum On

If you're willing to forego automatic figuring-out of the optimal number of columns, you can set a ${num_cols} , then use this:

pr -a -${num_cols} -t -s, -  | \
nl -v 0 --line-increment ${num_cols} | \
column -s, -t

and on your input, this gives:

     0  hobby       anger      experienced
     3  profession  golf       director
     6  code        telephone

which is more or less what you wanted.

3
KamilCuk On

This looks fine. The file input contains the code content you posted.

First I generate numbers 0 1 2 and the file content with 3 columns separted by ,.

Then for lines starting from the second line, lines are numbered.

AFter that, nice column is created.

$ ( seq 3; cat input; ) | paste -d, - - - | ( read;echo ",$REPLY"; nl -v 0 -i 3 -s, ) | column -t -s,
        1           2          3
     0  hobby       anger      experienced
     3  profession  golf       director
     6  code        telephone

Right pr exists, I usually use paste for columns:

(seq 3; cat input) | pr -a -3 -t -s, - | (read; echo ",$REPLY"; nl -v 0 -i 3 -s,) | column -t -s,

So:

indextable() {
   (seq "$1"; shift; cat "$@") |
       pr -a -"$1" -t -s, - |
       (read; echo ",$REPLY"; nl -v 0 -i "$1" -s,) |
       column -t -s,
}
indextable 3 input
5
qadzek On

A concise way to get pretty close to your desired result is column -c 50 -x input.txt | nl, which gives:

     1  hobby           anger           experienced
     2  profession      golf            director
     3  code            telephone

Long options format: column --output-width 50 --fillrows input.txt | nl