我有一些数据文本文件,它们的行是带错误的值,比如:
...
6 90.3785794742981 0.0952997386139722
40 1028.46336161948 4.41798447319325
...
第三列是相对于第二列的错误。我想写一个脚本,以更便于人类阅读的格式打印它们,也就是说,打印具有正确有效位数的值,并在括号之间的最后两个数字列表上打印错误,如下所示:
...
6 90.379(95)
40 1028.5(4.4)
...
使用正则表达式提取数字是不正确的,因为处理点很困难,而且它会截断数字而不是近似数字,所以我想我宁愿用printf
检索它们的大小,用bc
处理它们。
我为此编写的代码如下
#! /bin/bash
while read a v verr
do
ov=`printf %e $v`
ov=${ov/*e/}
overr=`printf "%e" $verr`
overr=${overr/*e/}
dov=$((1-$overr))
v=`echo "scale=0;$v*10^($dov)" | bc -l`
v=`printf %.0f $v`
printf "$a %f(%.0f)n" `echo "lenght=length($v);$v*10^($((-$dov)))" | bc -l` `echo "$verr*10^($dov)" | bc -l`
done < myfile.txt
我得到的是
6 90.379000(95)
40 1028.500000(44)
我的代码几乎可以工作,除了那些尾随零的出现。
我该如何摆脱它们?仅仅切割它们是不好的,因为它们的数字不是固定的,如果最后一个数字实际上是零,那么将它们全部切割会导致错误。
以下代码有效。
#! /bin/bash
while read a v verr
do
ov=`printf %e $v`
ov=${ov/*e/}
overr=`printf %e $verr`
overr=${overr/*e/}
dov=$((1-$overr))
v=`echo "scale=0;$v*10^($dov)" | bc -l`
v=`printf %.0f $v`
if [ $dov -gt 0 ]; then
# remember bc doesn't understand numbers in scientific notation,
# therefore we need to convert such numbers in regular notation.
u=`echo ${u} | sed 's/[eE]/\*10\^/' | sed 's/+//'`
verr=`echo ${verr} | sed 's/[eE]/\*10\^/' | sed 's/+//'`
u=`echo "$v*10^($((-$dov)))" | bc -l`
if [ $overr -eq 0 ]; then
uerr=`echo "$verr*10^($dov - 1)" | bc -l`
printf "$at%.${dov}f(%.1f)n" $u $uerr>>$s
else
uerr=`echo "$verr*10^($dov)" | bc -l`
printf "$at%.${dov}f(%.0f)n" $u $uerr>>$s
fi
else
echo $a "${v}(${verr})E$ov">>$s
fi
done < $f
它打印出我想要的格式化值。第一种情况测试它是否需要用指数表示法来表示结果,以获得正确的有效数字,第二种情况测试是否应该在错误中加一个点。
我还没有测试从底部开始的第三行代码,因为我现在不需要它,所以要小心,因为它可能不起作用。
编辑:我插入了两个sed调用来处理科学记数法数字。
如果您可以使用sed命令,您可以在printf之后添加一条sed语句来删除后面的零:
printf "$a %f(%.0f)n" `echo "lenght=length($v);$v*10^($((-$dov)))" | bc -l` `echo "$verr*10^($dov)" | bc -l` | sed 's/00*(/(/'