如何零垫一个序列的整数在bash,使所有有相同的宽度?

我需要循环一些值,

for i in $(seq $first $last)
do
does something here
done

对于$first$last,我需要它是固定长度5。所以如果输入是1,我需要在前面加零,这样它就变成了00001。例如,它循环到99999,但长度必须为5。

例如:000020004200212012312等等。

你知道我该怎么做吗?

360519 次浏览

使用printf和“%05d”,例如:

printf "%05d" 1

使用printf非常简单

[jaypal:~/Temp] printf "%05d\n" 1
00001
[jaypal:~/Temp] printf "%05d\n" 2
00002

在您的特定情况下,使用-f标志到seq可能是最简单的,以使它在输出列表时格式化数字。例如:

for i in $(seq -f "%05g" 10 15)
do
echo $i
done

将产生以下输出:

00010
00011
00012
00013
00014
00015

更一般地,bashprintf作为内置的,所以你可以用0填充输出,如下所示:

$ i=99
$ printf "%05d\n" $i
00099

你可以使用-v标志将输出存储在另一个变量中:

$ i=99
$ printf -v j "%05d" $i
$ echo $j
00099

注意,printf支持的格式与seq略有不同,因此您需要使用%05d而不是%05g

像这样使用awk:

awk -v start=1 -v end=10 'BEGIN{for (i=start; i<=end; i++) printf("%05d\n", i)}'

输出:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

更新:

作为纯bash的替代方案,你可以这样做来获得相同的输出:

for i in {1..10}
do
printf "%05d\n" $i
done

这样你就可以使用外部程序seq,也就是所有*nix版本上的不可用

你可以做得更简单

for i in {00001..99999}; do
echo $i
done

如果序列的结尾有最大的填充长度(例如,如果你想要5个数字,命令是seq 1 10000),那么你可以为seq使用-w标志-它自己添加填充。

seq -w 1 10

会产生

01
02
03
04
05
06
07
08
09
10

我用比我需要的更多的数字(零)来填充输出,然后使用tail来只使用我正在寻找的数字数量。注意,你必须在tail中使用'6'来获得最后5位数字:)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done

如果你想要N个数字,加10^N并删除第一个数字。

for (( num=100; num<=105; num++ ))
do
echo ${num:1:3}
done

输出:

01
02
03
04
05

这也会起作用:

for i in {0..9}{0..9}{0..9}{0..9}
do
echo "$i"
done

其他方式:

zeroos="000"
echo


for num in {99..105};do
echo ${zeroos:${#num}:${#zeroos}}${num}
done

转换任何数字的简单函数是:

function leading_zero(){


local num=$1
local zeroos=00000
echo ${zeroos:${#num}:${#zeroos}}${num}


}

1)。创建从1到1000的数字序列“seq”,并固定宽度“-w”(宽度由结束数字的长度决定,在本例中为1000的4位数字)。

2)。另外,使用'sed -n'选择您想要的数字(在本例中,我们选择数字1-100)。

3)。'echo'输出每个数字。数字存储在变量“i”中,使用“$”访问。

优点:这段代码非常干净。

缺点:'seq'不是所有Linux系统的本机(据我所知)

for i in `seq -w 1 1000 | sed -n '1,100p'`;
do
echo $i;
done

如果你只是想用0填充数字以达到固定长度,只需添加最接近10的倍数 如。对于2位数字,添加10^2,然后在显示输出之前删除第一个1

此解决方案适用于填充/格式化任意长度的单个数字,或使用for循环填充/格式化整个数字序列。

# Padding 0s zeros:
# Pure bash without externals eg. awk, sed, seq, head, tail etc.
# works with echo, no need for printf


pad=100000      ;# 5 digit fixed


for i in {0..99999}; do ((j=pad+i))
echo ${j#?}
done

在Mac OSX 10.6.8, Bash ver 3.2.48上测试

一种不使用外部进程分叉的方法是字符串操作,在一般情况下,它看起来像这样:

#start value
CNT=1


for [whatever iterative loop, seq, cat, find...];do
# number of 0s is at least the amount of decimals needed, simple concatenation
TEMP="000000$CNT"
# for example 6 digits zero padded, get the last 6 character of the string
echo ${TEMP:(-6)}
# increment, if the for loop doesn't provide the number directly
TEMP=$(( TEMP + 1 ))
done

这在WSL上也能很好地工作,在WSL中,分叉是一个非常繁重的操作。我有一个110000个文件列表,使用printf "%06d" $NUM花了1分钟多,上面的解决方案在1秒左右运行。

博士TL;

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

输入(模式1。慢):

$ seq 1 10 | xargs -n 1 printf "%05d\n"

输入(模式2。快):

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

输出(每种情况下的结果相同):

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

解释

我想建议以上的模式。这些实现可以作为命令使用,以便我们可以轻松地再次使用它们。在这些命令中,您需要关心的是转换后的数字的长度。(比如将数字%05d改为%09d。)另外,它也适用于其他解决方案,如以下。这个示例太依赖于我的环境,所以您的输出可能不同,但我认为您可以很容易地看出它的有用性。

$ wc -l * | awk '{printf("%05d\n", $1)}'
00007
00001
00001
00001
00013
00017
00001
00001
00001
00043

就像这样:

$ wc -l * | awk '{printf("%05d\n", $1)}' | sort | uniq
00001
00007
00013
00017
00043
此外,如果您以这种方式编写,我们还可以异步执行命令。(我找到了一篇不错的文章: # EYZ0) < / p >

免责声明:我不确定这一点,我不是*nix专家。

性能测试:

超级慢:

$ time seq 1 1000 | xargs -n 1 printf "%09d\n" > test
seq 1 1000  0.00s user 0.00s system 48% cpu 0.008 total
xargs -n 1 printf "%09d\n" > test  1.14s user 2.17s system 84% cpu 3.929 total

相对速度:

for i in {1..1000}
do
printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  0.01s user 0.01s system 74% cpu 0.021 total




for i in {1..1000000}
do
printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  7.10s user 1.52s system 99% cpu 8.669 total

快速:

$ time seq 1 1000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000  0.00s user 0.00s system 47% cpu 0.008 total
awk '{printf("%09d\n", $1)}' > test  0.00s user 0.00s system 52% cpu 0.009 total




$ time seq 1 1000000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000000  0.27s user 0.00s system 28% cpu 0.927 total
awk '{printf("%09d\n", $1)}' > test  0.92s user 0.01s system 99% cpu 0.937 total

如果必须实现更高性能的解决方案,可能需要其他技术,而不是使用shell脚本。

你不需要awk——seqjot就足够了:

% seq -f '%05.f' 6     # bsd-seq
00001
00002
00003
00004
00005
00006


% gseq -f '%05.f' 6    # gnu-seq
00001
00002
00003
00004
00005
00006


% jot -w '%05.f' 6
00001
00002
00003
00004
00005
00006

......除非你要进入bigint领域:

% gawk -Mbe '


function __(_,___) {
return +_<+___?___:_
}
BEGIN {
_+=_^=_<_
____="%0*.f\n"
} {
___=__($--_, !+$++_)
_____=__(++_+--_, length(______=+$NF))
do {
printf(____,_____,___)
}  while (___++<______)
                                                       

}' <<< '999999999999999999996 1000000000000000000003'


0999999999999999999996
0999999999999999999997
0999999999999999999998
0999999999999999999999
1000000000000000000000
1000000000000000000001
1000000000000000000002
1000000000000000000003

——————————————————————————————————————————————————

如果您需要打印出巨大的范围的数字,那么这种方法可能会更快一些-

  • 打印从1到100万的每一个整数,左零填充到9位宽,在0.049s

  • *< >强警告< / >强:我没有空闲时间让它覆盖所有输入范围::这只是一个接受10次方增量的概念证明

——————————————————————————————————————————————————

 ( time ( LC_ALL=C mawk2 '
 

function jot(____,_______,_____,_,__,___,______) {
if(____==(____^!____)) {
return +____<+_______\
? sprintf("%0*.f",_______,____)\
: +____
}
_______= (_______-=____=length(____)-\
(_=!(_<_)))<+_ \
? "" \
: sprintf("%0*.f",_______,!_)
__=_= (!(__=_+=_+_))(__=(-+--_)+(__+=_)^++_)\
(__+=_=(((_--^_--+_++)^++_-_^!_)/_))(__+_)
_____= "."
gsub(_____,"\\&&",__)
____—-
do {
gsub(_____,__,_)
_____=_____"."
} while(—____)


gsub(_____,(_______)"&\n",_)
sub("^[^\n]+[\n]","",_)
sub(".$",""~"",_______)
     

return \
(_)(_______)\
sprintf("%0*.f",length(_____),__<__)


} { print jot($1,$2) }' <<< '10000000 9'
  

) | pvE9 ) |xxh128sum |ggXy3 | lgp3


sleep 2
( time ( LC_ALL=C jot 1000000 |
LC_ALL=C mawk2 '{ printf("%09.f\n", $1) }'
 

) | pvE9 ) |xxh128sum |ggXy3 | lgp3




out9: 9.54MiB 0:00:00 [ 275MiB/s] [ 275MiB/s] [<=> ]
( LC_ALL=C mawk2  <<< '1000000 9'; )


0.04s user 0.01s system 93% cpu 0.049 total


e0491043bdb4c8bc16769072f3b71f98  stdin




out9: 9.54MiB 0:00:00 [36.5MiB/s] [36.5MiB/s] [  <=> ]
( LC_ALL=C jot 1000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )


0.43s user 0.01s system 158% cpu 0.275 total


e0491043bdb4c8bc16769072f3b71f98  stdin

当你做了1000万的时候,时差就变得很明显了:

 out9: 95.4MiB 0:00:00 [ 216MiB/s] [ 216MiB/s] [<=> ]
( LC_ALL=C mawk2  <<< '10000000 9'; )


0.38s user 0.06s system 95% cpu 0.458 total


be3ed6c8e9ee947e5ba4ce51af753663  stdin




out9: 95.4MiB 0:00:02 [36.3MiB/s] [36.3MiB/s] [ <=> ]
( LC_ALL=C jot 10000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )


4.30s user 0.04s system 164% cpu 2.638 total
 

be3ed6c8e9ee947e5ba4ce51af753663  stdin








out9: 95.4MiB 0:00:02 [35.2MiB/s] [35.2MiB/s] [ <=> ]


( LC_ALL=C python3 -c '__=1; ___=10**7;


[ print("{0:09d}".format(_)) for _ in range(__,___+__) ]'


) | pvE9 ) | xxh128sum |ggXy3 | lgp3 ;  )


2.68s user 0.04s system 99% cpu 2.725 total
 

be3ed6c8e9ee947e5ba4ce51af753663  stdin