假设我有一个文件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 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€
其中列用tabstop(也称为t
(分隔
通常我用一个小工具column -ts $'t' order.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行的情况下,该工具输出一个column: line too long
并退出。
我正在寻找的是一个解决方案,为我生成这样的输出:
# 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€
处理好长描述并在固定宽度后打印Amount、Price和Sum,同时拆分字符串以在Amount、Price和Sum行后打印剩余部分,这绝非易事。分割字符串的方法不止几种,还有更多更优雅的方法,但一个暴力的例子会给你一个想法。你可以把它整理成你认为合适的样子。只需通过更改dwidth变量或在文件名后提供所需的宽度作为第二个参数来设置宽度。
这假设您的输入格式与您描述的一样,字段由tabs
分隔,例如:#tDescriptiontAmounttPricetSum
#!/bin/bash
test -r "$1" || {
printf "Error: insufficient input, usage ${0//*//} <orders file>nn"
exit 1
}
oifs=$IFS # set IFS to only break on tab or newline
IFS=$'tn'
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 %-8sn" $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 " %-*sn" $dwidth "${desc:$strt:$i}" # print to width
else
printf " %-*sn" $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 %-8sn" $num $dwidth $desc $amt $price $sum
fi
done < "$1"
exit 0
输出:$ 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€
输出:$ 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€