bash 脚本中 printf 的奇怪问题:“09”和“08”是无效数字,“07”和“06”很好
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8078167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bizarre issue with printf in bash script:"09" and "08" are invalid numbers, "07" and "06" are fine
提问by Richard
This is my bash script - I just want to left-pad a set of numbers with zeroes:
这是我的 bash 脚本 - 我只想用零填充一组数字:
printf "%04d" "09"
printf "%04d" "08"
printf "%04d" "07"
printf "%04d" "06"
Output:
输出:
./rename.sh: line 3: printf: 09: invalid number
0000
./rename.sh: line 4: printf: 08: invalid number
0000
0007
0006
What...?
什么...?
Only 09 and 08 are causing the problem: every other number in my sequence seems to be OK.
只有 09 和 08 导致了问题:我序列中的所有其他数字似乎都可以。
回答by glglgl
If you have your "09"
in a variable, you can do
如果你有"09"
一个变量,你可以做
a="09"
echo "$a"
echo "${a#0}"
printf "%04d" "${a#0}"
Why does this help? Well, a number literal starting with 0
but having no x
at the 2nd place is interpreted as octal value.
为什么这有帮助?好吧,以 开头0
但x
在第二位没有的数字文字被解释为八进制值。
Octal value only have the digits 0
..7
, 8
and 9
are unknown.
八进制值只有数字0
.. 7
,8
并且9
是未知的。
"${a#0}"
strips one leading 0
. The resulting value can be fed to printf
then, which prints it appropriately, with 0
prefixed, in 4 digits.
"${a#0}"
带一个领先0
。结果值可以输入printf
then,然后0
以 4 位数字的前缀适当地打印它。
If you have to expect that you get values such as "009"
, things get more complicated as you'll have to use a loop which eliminates all excess 0
s at the start, or an extglob
expression as mentioned in the comments.
如果您必须期望获得诸如 的值"009"
,事情会变得更加复杂,因为您必须使用一个循环来消除开始时所有多余的0
s,或者使用extglob
注释中提到的表达式。
回答by Oliver Charlesworth
Numbers beginning with "0" are treated as octal (i.e. base-8). Therefore, "8" and "9" aren't valid digits.
以“0”开头的数字被视为八进制(即基数为 8)。因此,“8”和“9”不是有效数字。
See http://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic.
请参阅http://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic。
This behaviour is inherited from languages like C.
这种行为是从 C 等语言继承而来的。
回答by morgant
Bash's numeric arithmetic evaluation syntax (( ... ))
can convert to base 10 (therefor ensuring correct interpretation) with the following syntax: (( 10#$var ))
. Or, in the case of a raw number: (( 10#08 ))
. Very simple & clean and can be used anywhere you're sure the base should be 10, but can't guarantee a leading zero won't be included.
Bash 的数字算术计算语法(( ... ))
可以使用以下语法转换为基数 10(以确保正确解释):(( 10#$var ))
. 或者,对于原始数字:(( 10#08 ))
. 非常简单和干净,可以在任何你确定基数应该是 10 的地方使用,但不能保证不包括前导零。
So, in your example it would be as follows:
因此,在您的示例中,它将如下所示:
printf "%04d\n" $(( 10#09 ))
printf "%04d\n" $(( 10#08 ))
printf "%04d\n" $(( 10#07 ))
printf "%04d\n" $(( 10#06 ))
Producing the following output:
产生以下输出:
0009
0008
0007
0006
With this syntax, since you're then working with the value of the variable instead of variable itself, incrementors (( var++ ))
& decrementors (( var-- ))
won't work, but can still be relatively cleanly implemented as var=$(( 10#var + 1 ))
and var=$(( 10#var - 1 ))
, respectively.
使用此语法,由于您随后使用的是变量的值而不是变量本身,因此增量器(( var++ ))
和减量器(( var-- ))
将不起作用,但仍然可以分别相对干净地实现为var=$(( 10#var + 1 ))
和var=$(( 10#var - 1 ))
。
I first encountered this solution here, but this answer to a similar Stack Overflow questionalso demonstrates it.
我第一次在这里遇到了这个解决方案,但是这个对类似 Stack Overflow 问题的回答也证明了这一点。
回答by Ross Aiken
Floating point is handled differently:
浮点的处理方式不同:
printf "%04.f" "009"
This gives the correct output, without dealing with any fancy bashisms (per @Oli Charlesworth's answer, 0*** is treated as octal, but I believe that Bash ignores octal/hex identifiers for floating-point numbers)
这给出了正确的输出,而无需处理任何花哨的 bashisms(根据 @Oli Charlesworth 的回答,0*** 被视为八进制,但我相信 Bash 会忽略浮点数的八进制/十六进制标识符)
回答by Nathan Fellman
Just to add to Oli's answer, in order to pad a number with zeroes it is enough to put a 0
after the %
, as you did:
只是添加到Oli 的答案中,为了用零填充一个数字,就像你所做的那样,0
在 之后放置 a 就足够了%
:
printf "%04d" "9"
printf "%04d" "9"
回答by carlo
Adding *
makes shell parameter expansion matching greedy (see, for example, Shell Tipps: use internal string handling)!
添加*
使 shell 参数扩展匹配贪婪(例如,请参阅Shell Tipps:使用内部字符串处理)!
# strip leading 0s
- a="009"; echo ${a##0}
+ a="009"; echo ${a##*0}
回答by F. Hauri
Why did “09” and “08” are invalid numbers, “07” and “06” are fine
为什么“09”和“08”是无效数字,“07”和“06”是好的
Because preceding integer by 0
is a conventional shortcut meaning number is octal.
因为前面的 integer by0
是一个传统的快捷方式,意味着number 是八进制。
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
How to work with this?
如何处理这个问题?
Using bash integer: preceding number by 10#
使用 bash 整数:前面的数字由 10#
Under bash, you could precise by this way, which baseis used for number
在bash下,你可以通过这种方式精确,哪个基数用于数字
echo $(( 10#0100))
100
echo $(( 10#0900))
900
echo $(( 10#0900 ))
900
and
和
echo $(( 8#100 ))
64
echo $(( 2#100 ))
4
Of course!
当然!
There are only 10 types of people in the world: those who understand binary, and those who don't.
世界上只有10种人:懂二进制的和不懂二进制的。
Using bashParameter Expansion
使用bash参数扩展
For this, you have to use a variable
为此,您必须使用一个变量
a=09
echo ${a#0}
9
This will work fine until you just have only one 0
to drop.
这将正常工作,直到您只能0
丢弃一个。
a=0000090
echo ${a#*0}
000090
echo ${a##0}
000090
For this, you coul use extglob
feature:
为此,您可以使用extglob
功能:
echo ${a##*(0)}
0000090
shopt -s extglob
echo ${a##*(0)}
90
Using floating point
with printf
使用floating point
与printf
printf "%.0f\n" 09
9
I like using -v
option of printf
for setting some variable:
我喜欢使用-v
选项printf
来设置一些变量:
printf -v a %.0f 09
echo $a
9
or even if
或者即使
a=00090
printf -v a %.0f $a
echo $a
90
回答by John Kolvereid
Much simpler to convert from octal to decimal:
从八进制转换为十进制要简单得多:
nm=$((10#$nm))
回答by SanjeethBoddi
if a=079
first, remove the trailing zeros by
如果a=079
首先,删除尾随零
a=`echo $a | sed 's/^0*//'`
then do the zero-padding
然后做零填充
printf "%04d" $a