如何迭代“[AZ][0-9]*”形式的字符串,或者例如:“A000001”?
收到变量后我拆分:
current_=$(mysql -h"$mysqlhost" -u"$mysqluser" -p"$PASS" "$DBNAME" -se "SELECT current_ FROM $GLOBALDB;")
current_number=$(echo $current_ | grep -oh "[0-9]*")
current_letter=$(echo $current_ | grep -oh "[A-Z]*")
但是当我尝试添加 1 时:
# add 1 & keep all leading zeros "000001"
next_number=$(printf %06d $(($current_number + 1)))
它计数到“000009”并回滚到“000000”。
我加入如下:
next_=$(echo "$current_letter$next_number")
关于字母迭代,我正在考虑使用关联数组?或者大括号扩展{A..Z}
,但这是一个完全不同的问题。
答案1
在 中bash
,带有前导零的数字被视为八进制。要强制bash
将它们视为十进制,您可以添加10#
前缀:
next_number=$(printf %06d "$((10#$current_number + 1))")
或者使用 bash 3.1 或更高版本,以避免分叉:
printf -v next_number %06d "$((10#$current_number + 1))"
(请注意,它不适用于负数,如中10#-010
所示,因此和都扩展到)。10#0 - 010
bash
$((10#-10))
$((-10#-10))
-8
也可以看看:
$ printf 'A%06d\n' {5..12}
A000005
A000006
A000007
A000008
A000009
A000010
A000011
A000012
或者:
$ printf '%s\n' {A..C}{00008..00012}
A00008
A00009
A00010
A00011
A00012
B00008
B00009
B00010
B00011
B00012
C00008
C00009
C00010
C00011
C00012
或者:
$ seq -f A%06g 5 12
A000005
A000006
A000007
A000008
A000009
A000010
A000011
A000012
答案2
Perl 来拯救:
perl -E '$x = "A001"; say $x++ for 1 .. 1002'
输出:
A001
A002
A003
A004
A005
A006
A007
A008
A009
A010
A011
...
A996
A997
A998
A999
B000
B001
B002
++ 运算符可以处理字母和数字。
答案3
由于历史原因,Bourne/POSIX 风格 shell 中的数值运算会将前导0
数字的整数常量解析为八进制而不是十进制。所以08
在算术运算中是一个语法错误, 的后继07
是 8,并且010
等价于8
。
您可以使用普通算术,然后在使用内置函数打印数字时填充数字printf
。
next_number=$(($current_number + 1))
printf -v padded_next_number %06d "$next_number"
-v
的选项是printf
bash 特定的; POSIX 方式是
next_number=$(($current_number + 1))
padded_next_number=$(printf %06d "$next_number")
这是另一种方法,它在没有命令的历史系统中很有用printf
,并且在少数没有printf
内置命令的 shell 中仍然可以提高性能。不要从 1 开始计数,而是从 1000001 开始计数。这样,您的数字就不必有前导零。使用该号码时,请去掉前导1
数字。
number=1000000
while … ; do
number=$((number+1))
echo "${number#1}"
…
done