I’m trying to center-align a column using the command column.
The output should look like this:
temperatures
50
12
89
63
How can I do this?
I’m trying to center-align a column using the command column.
The output should look like this:
temperatures
50
12
89
63
How can I do this?
I wrote this answer before noticing that you want to use the column command, but if that isn’t a requirement, you can center text with this bash shell script:
#!/bin/bash
set -e # exit the script if something goes wrong
width=12
data="temperatures 50 12 89 63"
for word in $data; do
strlen=$(printf $word | wc -c)
w=$(( ($width - $strlen)/2 ))
printf "%${w}s%s\n" "" $word
done
How it works:
$width is the column widthfor loop prints every word in $data$strlen is the length of the current word, in bytes.$w is the number of spaces to print before the word to make it centered.printf prints $w spaces, followed by the wordOutput:
temperatures
50
12
89
63
This script will only work for single-byte text encodings. You would need to change the strlen line to handle text containing a , for example.
Given some file,
temps,temperatures,heatness
500,50,50
1212,12,12
899,89,8989
63,6363,63
the column command could give you aligned columns, but no other special adjustment of them:
$ column -t -s, file
temps temperatures heatness
500 50 50
1212 12 12
899 89 8989
63 6363 63
With a small-ish awk script, we can do centering:
$ awk -F, -f center-cols.awk file
temps temperatures heatness
500 50 50
1212 12 12
899 89 8989
63 6363 63
$ awk -F, -v OFS='|' -f center-cols.awk file
temps|temperatures|heatness
500 | 50 | 50
1212 | 12 | 12
899 | 89 | 8989
63 | 6363 | 63
The center-cols.awk script might look like
function center(w, string, space, before, after) {
space = w - length(string) # number of spaces in total to fill
before = int(space/2) # spaces before string
after = space - before # the rest of spaces after
return sprintf("%*s%s%*s", before, "", string, after, "")
}
FNR == 1 {
for (i = 1; i <= NF; ++i)
width[i] = length($i)
}
{
for (i = 1; i <= NF; ++i)
$i = center(width[i], $i)
print
}
The script centers each column in the data according to the width of the header column (the first row) of each row. This means that rows with data that is longer than the header will still be misaligned. This restriction simplifies the script's implementation (one would otherwise have to parse the file twice, once to find the maximum column width for each column, and once to reformat the data).
The script first gets the width of each header column and saves these into the width array. It then rewrites each column using the center function.
The center function takes a width and a string, and returns a string centered within that width, with flanking spaces filling the unused space. The resulting string is constructed using sprintf() with which the flanking spaces are written using the %*s format specifier. This specifier takes a width and a string, and we give it the calculated width and an empty string for both the space at the start and the back of the actual data (the empty string would be formatted to the given width).
Once all columns of a row has been reformatted, the line is printed.
By parsing the file twice, we can find the maximum width of each column. This way we don't have to rely on the header row defining the width of tho columns:
function center(w, string, space, before, after) {
space = w - length(string) # number of spaces in total to fill
before = int(space/2) # spaces before string
after = space - before # the rest of spaces after
return sprintf("%*s%s%*s", before, "", string, after, "")
}
NR == 1 {
for (i = 1; i <= NF; ++i)
width[i] = length($i)
next
}
FNR == NR {
for (i = 1; i <= NF; ++i)
if (width[i] < length($i))
width[i] = length($i)
next
}
{
for (i = 1; i <= NF; ++i)
$i = center(width[i], $i)
print
}
Running this on a file with short column headers:
$ awk -F, -v OFS='|' -f center-cols.awk file file
t | a | b
500 | 50 | 50
1212| 12 | 12
899 | 89 |8989
63 |6363| 63
Note that we need to give the filename twice on the command line.