In bash (or POSIX shell), your primary built-in tool for formatting is printf
. You can read the first 4-columns of each line and the rest in some dummy variable and then print them with printf
formatting the columns to a specific width each, as required:
#!/bin/bash
while read -r c1 c2 c3 c4 stuff; do
printf "%5s %4s %8s %5s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"
exit 0
Input
$ cat dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.5 0 0 1
Output
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.5 0 0 1
printf
in bash takes the same format string and format specifiers as it does in C. You can read about all the things you can do with formatting in man 3 printf
. In addition bash adds a few, like printf -v varname "fmt string"
to format and save the results in varname
.
One limitation on the format string is padding. While you can 0
pad on the left, you cannot 0
pad a number on the right. Regardless of whether you use a %s
a string conversion or %5.1f
a floating point conversion, you are limited to left-padding and field-width specification.
You can, of course, check the length of each variable before printing, and 0
pad on the right that way, but that is about the point where you start asking can a external shell utility do that for me.... But, for completeness:
#!/bin/bash
while read -r c1 c2 c3 c4 stuff; do
while [ ${#c4} -lt 5 ]; do
c4="${c4}0"
done
printf "%s %s %s %s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"
exit 0
Output
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1