Awk四舍五入的数字

时间:2014-08-29 10:28:37

标签: shell unix awk

a=`echo 9.1200 | awk '{ if ($0 ~ /\./){ sub("0*$","",$0); sub ("\\.$","",$0);} print}'`
$a

上面的awk在shell脚本中返回9.1。但是在unix控制台中执行相同的awk时 它返回的值为9.12

为什么awk将数字四舍五入以及如何避免这种情况?

以下是示例输入和输出文件值

Sample input:
10
10.1
10.0
10.00
10.0000
10.0000000
10.58770
10.580
10.2555550003

Expected Output:
10
10.1
10
10
10
10
10.5877
10.58
10.2555550003

2 个答案:

答案 0 :(得分:3)

awk没有四舍五入,你用最后的sub()命令剥离最后一位数字。看:

$ a=`echo 9.1200 | awk '{ if ($0 ~ /\./){ sub("0*$","",$0); sub ("\\.$","",$0);} print}'
$ echo $a
9.1

$ a=`echo 9.1200 | awk '{ if ($0 ~ /\./){ sub("0*$","",$0); sub ("[.]$","",$0);} print}'`
$ echo $a
9.12

您的命令行出现了一些问题。

  1. sub()将RE作为它的第一个arg,因此使用显式RE时的概要是sub(/RE/,...)而不是sub("RE",...)(google awk解析字符串文字)。
  2. 默认情况下,sub()的第3个arg为$ 0,因此无需显式添加 它。
  3. 您不需要多次调用sub()来剥离结尾 字符串,只是一个简单的ERE。
  4. awk脚本是<condition> { <action> }块,所以不要这样做 行动区内的条件。
  5. 将字符串转换为数字的自然方法就是使用a 数字运算符就可以了,不要试图操纵字符串来查看 像一个数字。
  6. 不要使用已弃用的反引号来调用命令,因为除其他外,它们会解释反斜杠,因此您的awk命令会看到sub("\.$"..而不是您想要的sub("\\.$"..
  7. 始终引用shell变量
  8. 这是一个有效的语法,可以使用字符串操作来执行您尝试执行的操作:

    $ a=$(echo 9.1200 | awk '/\./{ gsub(/\.0*$/,""); print}')
    $ echo "$a"
    9.12
    

    但这更简单:

    $ a=$(echo 9.1200 | awk '/\./{ print $0+0 }')
    $ echo "$a"
    9.12
    

    如果您的输入数据始终为数字,则根本不需要/\./的测试:

    $ a=$(echo 9.1200 | awk '{print $0+0}')
    $ echo "$a"
    9.12
    

    你遇到的主要问题是使用反斜杠,所以让我稍微解决一下。当您编写包含RE元字符的RE(例如.),您希望将其视为文字字符时,您有2个选项:

    /\./
    

    /[.]/
    

    我们假设您决定使用前者。一切顺利,直到您决定使用字符串分隔符而不是RE分隔符。字符串文字被解释两次,一次是在读取脚本时,一次是在执行时,为了逃避RE元字符,你需要将其转义两次,例如:

    "\\."
    

    现在让我们假设您决定调用awk脚本将输出保存在shell变量中。你有两个选择:

    var=`awk '...'`
    

    或:

    var=$(awk '...')
    

    当你使用后者时没有问题但是当你使用前者时,```语法本身会将反斜杠对解释为单反斜杠,所以你需要添加一个反斜杠以逃避. ,即:

    var=`awk '... "\\\." ...'`
    

    显然逃避现在已经失控。

    所以 - 为了避免反斜杠地狱,在使用RE时尽可能使用RE分隔符/.../而不是字符串分隔符"...",并且在执行shell脚本时使用$(...)而不是旧样式` ...`。

    * RE需要字符串分隔符的时间是将文字RE段与变量连接或在变量中保存RE时的情况,例如: var="a.b"; sub(var,"")sub(var".*","")

答案 1 :(得分:1)

如果您只是想删除前导零和尾随零,则会执行以下操作:

echo 09.1200 | awk '{ print +$0 }'

或者有些人更喜欢(更广泛的兼容性):

echo 09.1200 | awk '{ print $0+0 }'

这两者中的任何一个都会导致awk将输入转换为数字。 (请注意the first one will not work on all versions of awk

两种情况下的输出(使用gawk):

9.12

为了获得更高的精确度,您可以使用以下内容:

awk '{ printf "%.12g\n", $0 }' file

12指定最大小数位数。

作为@Jotne has suggested,您应该使用a=$(awk '{ printf "%.12g\n", $0 }' file)而不是使用反引号。这样做会导致您的原始代码工作,以及我建议的方法。