bash中的printf:“09”和“08”是无效数字,“07”和“06”很好

问题描述 投票:0回答:9

这是我的 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 导致了问题:我的序列中的所有其他数字似乎都正常。

bash shell printf
9个回答
46
投票

如果你的

"09"
在变量中,你可以这样做

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

为什么这有帮助?那么,以

0
开头但第二位没有
x
的数字文字将被解释为八进制值。

八进制值只有数字

0
..
7
8
9
未知。

"${a#0}"
剥离一个前导
0
。然后可以将结果值输入到
printf
,然后以 4 位数字的形式正确打印它,并带有
0
前缀。

如果您必须期望获得诸如

"009"
之类的值,事情会变得更加复杂,因为您必须使用一个循环来消除开始时所有多余的
0
,或者使用
extglob
表达式,如中提到的评论。


31
投票

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 ))分别是 

我第一次遇到这个解决方案在这里,但是这个类似的堆栈溢出问题的答案也演示了它。


21
投票

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

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

此行为是从 C 等语言继承的。


9
投票

浮点数的处理方式不同:

printf "%04.f" "009"

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


4
投票

只是添加到Oli的答案,为了用零填充数字,只需在

0
后面放置一个
%
就足够了,就像你所做的那样:

printf "%04d" "9"


4
投票

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

护理!!

07
工作正常:

printf 'Entered number: %d.\n' 07
Entered number: 7.

好的,但是:

printf 'Entered number: %d.\n' 07 070 0700
Entered number: 7.
Entered number: 56.
Entered number: 448.

因为在整数前面加上

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
printf
选项来设置一些变量:

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

或者即使

a=00090
printf -v a %.0f $a
echo $a
90

2
投票

添加

*
使 shell 参数扩展匹配变得贪婪(例如,参见 Shell Tipps:使用内部字符串处理)!

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

1
投票

如果

a=079
首先,通过

删除尾随零
a=`echo $a | sed 's/^0*//'`

然后进行零填充

printf "%04d" $a

1
投票

从八进制转换为十进制更简单:

nm=$((10#$nm))
© www.soinside.com 2019 - 2024. All rights reserved.