在bash脚本中printf的奇怪问题:“09”和“08”是无效数字,“07”和“06”都没问题

时间:2011-11-10 10:34:57

标签: bash shell printf

这是我的bash脚本 - 我只想用零填充一组数字:

printf "%04d" "09"
printf "%04d" "08"
printf "%04d" "07"
printf "%04d" "06"

输出:

./rename.sh: line 3: printf: 09: invalid number 
0000
./rename.sh: line 4: printf: 08: invalid number 
0000 
0007
0006

什么...?

只有09和08导致问题:我的序列中的每个其他数字似乎都没问题。

9 个答案:

答案 0 :(得分:26)

如果您在变量中有"09",则可以执行

a="09"
echo "$a"
echo "${a#0}"
printf "%04d" "${a#0}"

为什么这有帮助?好吧,从0开始但在第二位没有x的数字文字被解释为八进制值。

八进制值仅包含数字0 .. 789未知。

"${a#0}"删除一个前导0。结果值可以输入printf,然后以{4}数字前缀0进行相应的打印。

如果你不得不期望得到诸如"009"之类的值,那么事情会变得更复杂,因为你必须使用一个循环来消除开始时所有多余的0,或者{ {1}}表达式,如评论中所述。

答案 1 :(得分:20)

以“0”开头的数字被视为八进制(即基数为8)。因此,“8”和“9”不是有效数字。

请参阅http://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic

此行为继承自C。

等语言

答案 2 :(得分:18)

Bash的数值算术评估语法(( ... ))可以使用以下语法转换为基数10(因此确保正确解释):(( 10#$var ))。或者,如果是原始数字:(( 10#08 ))。非常简单&干净,可以在任何你确定基数应该是10的地方使用,但不能保证不包括前导零。

因此,在您的示例中,它将如下所示:

printf "%04d\n" $(( 10#09 ))
printf "%04d\n" $(( 10#08 ))
printf "%04d\n" $(( 10#07 ))
printf "%04d\n" $(( 10#06 ))

产生以下输出:

0009
0008
0007
0006

使用这种语法,因为您正在使用变量的值而不是变量本身,增量器(( var++ ))&递减器(( var-- ))将不起作用,但仍可以相对干净地实施为var=$(( 10#var + 1 ))var=$(( 10#var - 1 ))

我第一次遇到此解决方案here,但this answer to a similar Stack Overflow question也证明了这一点。

答案 3 :(得分:4)

只需要添加到Oli's answer,为了用零填充数字,就可以像0一样在%之后加上printf "%04d" "9"

{{1}}

答案 4 :(得分:3)

浮点的处理方式不同:

printf "%04.f" "009"

这给出了正确的输出,没有处理任何花哨的基础(根据@Oli Charlesworth的回答,0 ***被视为八进制,但我相信Bash忽略浮点数的八进制/十六进制标识符)

答案 5 :(得分:1)

添加*使shell参数扩展与贪婪匹配(例如,参见Shell Tipps: use internal string handling)!

# strip leading 0s
- a="009"; echo ${a##0}
+ a="009"; echo ${a##*0}

答案 6 :(得分:1)

为什么“ 09”和“ 08”是无效数字,为什么“ 07”和“ 06”是正确数字

因为在整数前面加0是常规的快捷方式,所以 数字是八进制的

printf "%d\n" 010 0100
8
64

printf "%o\n" 8 64 0100
10
100
100
printf "%04o\n" 8 64 0100
0010
0100
0100

如何使用它?

使用bash整数:10#前的数字

在bash下,您可以通过这种方式精确表示,其中 base 用于数字

echo $(( 10#0100))
100
echo $(( 10#0900))
900
echo $(( 10#0900 ))
900

echo $(( 8#100 ))
64
echo $(( 2#100 ))
4

当然!

  

世界上只有10种类型的人:懂二进制的人和不懂二进制的人。

使用 参数扩展

为此,您必须使用一个变量

a=09
echo ${a#0}
9

这将正常工作,直到您只放一个0为止。

a=0000090

echo ${a#*0}
000090
echo ${a##0}
000090

为此,您可以使用 extglob 功能:

echo ${a##*(0)}
0000090
shopt -s extglob
echo ${a##*(0)}
90

floating point printf

一起使用
printf "%.0f\n" 09
9

我喜欢使用-v的{​​{1}}选项来设置一些变量:

printf

或者即使

printf -v a %.0f 09
echo $a
9

答案 7 :(得分:0)

从八进制转换为十进制更简单:$ nm = $(((10#$ nm))

答案 8 :(得分:0)

如果a=079 首先,通过删除尾随零

a=`echo $a | sed 's/^0*//'`

然后进行零填充

printf "%04d" $a