如何将值+ -error格式的值/错误更改为值(错误)格式?

时间:2012-10-12 14:46:56

标签: bash printf numeric bc

我有一些数据文本文件,其行是带有错误的值,如下所示:

...
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)

我的代码几乎可以工作,除了那些尾随零的外观。

我如何摆脱它们?只是切割它们并不好,因为它们的数量不固定,并且将它们全部切割会导致最后一个数字实际为零的错误。

2 个答案:

答案 0 :(得分:0)

如果使用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*(/(/'

答案 1 :(得分:0)

以下代码有效。

#! /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 "$a\t%.${dov}f(%.1f)\n" $u $uerr>>$s
    else
    uerr=`echo "$verr*10^($dov)" | bc -l`
    printf "$a\t%.${dov}f(%.0f)\n" $u $uerr>>$s
    fi
else
    echo $a "${v}(${verr})E$ov">>$s
fi
done < $f

它打印按我想要的格式化的值。第一种情况测试是否需要以指数表示法表示结果才能获得正确的数字,第二种情况是测试它是否应该在错误中加上一个点。

我没有从底部测试第三行代码,因为我现在不需要它,所以要小心,因为它可能不起作用。

编辑:我插入两个sed调用来处理科学记数字。