If you have column(1)
, an old BSD tool, try column -t
, for pretty-printing tables.
To ensure empty cells are displayed, you could try the approach of inserting a single space in each empty cell (recognizable by two consecutive tabs). The idea is column(1)
should give the space character its own column but being a single character in width it should not affect the table dimensions or be visible in the output to humans.
generate_tsv |
awk '/\t\t/ { for (i = 0; i < 2; i++) gsub(/\t\t/, "\t \t") } 1' |
column -t -s $'\t'
The extra awk
inserted in the pipeline does the inserting of spaces into each empty cell, as described. 2 passes are necessary to handle 2 consecutive empty cells (\t\t\t
).
I think you're looking for expand
and/or unexpand
. It seems you're trying to ensure a \t
ab width counts as 8 chars rather than the single one. fold
will do that as well, but it will wrap its input to the next line rather than truncating it. I think you want:
expand < input | cut -c -80
expand
and unexpand
are both POSIX specified:
- The
expand
utility shall write files or the standard input to the standard output with \t
ab characters replaced with one or more space characters needed to pad to the next tab stop. Any backspace characters shall be copied to the output and cause the column position count for tab stop calculations to be decremented; the column position count shall not be decremented below zero.
Pretty simple. So, here's a look at what this does:
unset c i; set --;
until [ "$((i+=1))" -gt 10 ]; do set -- "$@" "$i" "$i"; done
for c in 'tr \\t \ ' expand; do eval '
{ printf "%*s\t" "$@"; echo; } |
tee /dev/fd/2 |'"$c"'| {
tee /dev/fd/3 | wc -c >&2; } 3>&1 |
tee /dev/fd/2 | cut -c -80'
done
The until
loop at top gets a set of data like...
1 1 2 2 3 3 ...
It printf
s this with the %*s
arg padding flag so for each of those in the set printf
will pad with as many spaces as are in the number of the argument. To each one it appends a \t
ab character.
All of the tee
s are used to show the effects of each filter as it is applied.
And the effects are these:
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
66
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8
105
Those rows are lined up in two sets like...
- output of
printf ...; echo
- output of
tr ...
or expand
- output of
cut
- output of
wc
The top four rows are the results of the tr
filter - in which each \t
ab is converted to a single space.
And the bottom four the results of the expand
chain.
Best Answer
Similar to cut , you can also do it with awk:
The difference is that awk handles better the white space than cut. This is useful if fields in each line are separated with more than one space.
For example if the file line is
A red
= one space separated, then cut solution as advised can do it also successfully, but if the line isA red
= 3 spaces , then cut will fail, while awk will succeed to get fields 1 and 2 or fields 1 and 3.Update:
As advised in comments (thanks don_crissti) this can also be done in pure awk:
Explanation: