如何使用具有前导零的数字变量进行bash算术运算?

5
我在一个bash脚本中有以下代码,其中“values”是一个由换行分隔的数字变量,其中一些数字有前导0,我试图遍历values中的每个值并将每个值添加到变量“sum”中。
sum=0
while read line; do
    sum=$(( sum + line ))
done <<< "$values"

这段代码给我报错:"value too great for base (error token is "09")",据我所知,这是因为bash算术表达式将值"line"解释为八进制值,因为它有一个前导零。

我该如何让bash将"line"的值解释为十进制值?(例如:09 -> 9)在这个bash算术表达式中?


@Rafael,...为什么你认为这意味着假设是错误的?02仍然是2,而3是十进制,因为它没有任何前导零。因此,无论02是八进制还是十进制,你都会得到5 - Charles Duffy
@CharlesDuffy:我真不敢相信我错过了那个。 - Rafael
3个回答

16
你可以通过显式地使用10#来强制使用十进制,覆盖“前导0表示八进制”的行为。
sum=$(( 10#$sum + 10#$line ))

请注意,虽然在算术上下文中通常可以省略变量引用中的$,但在此情况下需要使用它。另外,如果变量有前导空格(在第一个"0"之前),它将不能正确解析。


2

要去掉单个前导零:

"${line#0}"

要去除任意数量的前导零:

"${line##+(0)}"

例如:

$ line=009900
$ echo "${line##+(0)}"
9900

0

你可以使用类似以下的代码,轻松去除前导零:

shopt extglob on
x="${x##+(0)}"
[[ -z "${x}" ]] && x=0

这将删除所有前导零,然后捕获它是全部为零的情况(导致空字符串),将其恢复为单个零。

以下函数(和测试代码)将展示此过程:

#!/bin/bash

stripLeadingZeros() {
    shopt -s extglob
    retVal="${1##+(0)}"
    [[ -z "${retVal}" ]] && retVal=0
    echo -n "${retVal}"
}

for testdata in 1 2 3 4 5 0 09 009 00000009 hello 00hello ; do
    result="$(stripLeadingZeros ${testdata})"
    echo "${testdata} -> ${result}"
done

那个的输出是:

1 -> 1
2 -> 2
3 -> 3
4 -> 4
5 -> 5
0 -> 0
09 -> 9
009 -> 9
00000009 -> 9
hello -> hello
00hello -> hello

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接