Reputation: 875
Let's say I have a file orders.txt
which contains something like:
# Description Amount Price Sum
1 Beermat 1000 0,01€ 10€
2 Glass 100 1€ 100€
3 Long description 1 10€ 10€
4 An even longer description 1 10€ 10€
5 An extra long description, for real! 1 10€ 10€
6 An extra long description, almost max. length 1 10€ 10€
7 Long description for some really fancy product and unfortunately this description is too long to fit into one line - bad luck! 1 10€ 10€
8 This line isn’t shown afterwards 1 1€ 1€
Where the columns are separated with a tabstop a.k.a. \t
Usually I format these things with a little tool column -ts $'\t' order.txt
which results in something like:
# Description Amount Price Sum
1 Beermat 1000 0,01€ 10€
2 Glass 100 1€ 100€
3 Long description 1 10€ 10€
4 An even longer description 1 10€ 10€
5 An extra long description, for real! 1 10€ 10€
6 An extra long description, almost max. length 1 10€ 10€
This works fine as long as one line doesn't exceed the line width of your terminal window. So in case of line #7 this tool outputs a column: line too long
and exits.
What I'm looking for is a solution to generate me an output like this one:
# Description Amount Price Sum
1 Beermat 1000 0,01€ 10€
2 Glass 100 1€ 100€
3 Long description 1 10€ 10€
4 An even longer description 1 10€ 10€
5 An extra long description, for real! 1 10€ 10€
6 An extra long description, almost max. length 1 10€ 10€
7 Long description for some really fancy product 1 10€ 10€
and unfortunately this description is too long
to fit into one line - bad luck!
8 This line isn’t shown afterwards 1 1€ 1€
Upvotes: 0
Views: 176
Reputation: 84561
Well handling the long descriptions and printing the Amount, Price and Sum after a fixed width while splitting the string to print the remainder after the Amount, Price and Sum line is not trivial. There are more than a few ways to split strings, and more ways that are more elegant, but a brute-force example will give you an idea. You can tidy this up as you see fit. Just set your width by changing the dwidth variable or providing the desired width as a second argument after the filename.
This assumes your input format is as you described, with fields separated by tabs
for example: #\tDescription\tAmount\tPrice\tSum
#!/bin/bash
test -r "$1" || {
printf "Error: insufficient input, usage ${0//*\//} <orders file>\n\n"
exit 1
}
oifs=$IFS # set IFS to only break on tab or newline
IFS=$'\t\n'
dwidth=${2:-50} # set the print width you want for description (default 50)
i=0
while read num desc amt price sum || test -n "$num"; do
# test description > width, if so print only first 50 (or on word break)
if test "${#desc}" -ge "$dwidth" ; then
for ((i=$dwidth; i>0; i--)); do
test "${desc:$i:1}" = ' ' && break
done
end=$i
printf "%2s %-*s %-8s %-8s %-8s\n" $num $dwidth "${desc:0:end}" $amt $price $sum
remain=$((${#desc}-$end)) # calculate remaining chars to print
while test "$remain" -gt 0; do # while characters remain
strt=$((end+1)) # start printing at last end
if test "$remain" -gt "$dwidth"; then # test if more than width remain
for ((i=$dwidth; i>0; i--)); do # if so, break on word
test "${desc:$((strt+i)):1}" = ' ' && break
done
end=$((strt+i)) # set end equal to start + chars in words
printf " %-*s\n" $dwidth "${desc:$strt:$i}" # print to width
else
printf " %-*s\n" $dwidth "${desc:$strt}" # print rest and break
break
fi
remain=$((${#desc}-$end)) # calculate new remaining chars
done
else # if description not > width, just print it
printf "%2s %-*s %-8s %-8s %-8s\n" $num $dwidth $desc $amt $price $sum
fi
done < "$1"
exit 0
output: $ bash orders.sh orders.txt
# Description Amount Price Sum
1 Beermat 1000 0,01€ 10€
2 Glass 100 1€ 100€
3 Long description 1 10€ 10€
4 An even longer description 1 10€ 10€
5 An extra long description, for real! 1 10€ 10€
6 An extra long description, almost max. length 1 10€ 10€
7 Long description for some really fancy product and 1 10€ 10€
unfortunately this description is too long to fit
into one line - bad luck!
8 This line isn’t shown afterwards 1 1€ 1€
output: $ bash orders.sh orders.txt 60
# Description Amount Price Sum
1 Beermat 1000 0,01€ 10€
2 Glass 100 1€ 100€
3 Long description 1 10€ 10€
4 An even longer description 1 10€ 10€
5 An extra long description, for real! 1 10€ 10€
6 An extra long description, almost max. length 1 10€ 10€
7 Long description for some really fancy product and 1 10€ 10€
unfortunately this description is too long to fit into one
line - bad luck!
8 This line isn't shown afterwards 1 1€ 1€
Upvotes: 3