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
答案 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
您的命令行出现了一些问题。
sub(/RE/,...)
而不是sub("RE",...)
(google awk解析字符串文字)。<condition> { <action> }
块,所以不要这样做
行动区内的条件。sub("\.$"..
而不是您想要的sub("\\.$"..
。这是一个有效的语法,可以使用字符串操作来执行您尝试执行的操作:
$ 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)
而不是使用反引号。这样做会导致您的原始代码工作,以及我建议的方法。