以下 bash 脚本适用于 1..1000 的高计数范围
由于计数范围较高,大于 1..1000000,因此需要一些时间才能启动。总的来说,它运行良好。
for i in {1..10}; do
printf '\r%2d' $i
sleep 1
done
printf '\n'
对于从 99..1 开始的数字范围倒数,它工作得很好。
对于从高于 99 开始的数字范围进行倒计时,pe 100..1 输出会打印过多带有零的数字。你怎样才能避免这种情况呢?
答案1
您的问题:
该命令需要一些时间才能启动。这是由于您对循环使用了大括号扩展。扩展必须首先扩大,这意味着 shell 必须创建一个列表,其中包含要循环的范围内的每个数字。这需要时间(创建列表)和内存(存储列表)。在我的机器上,我可以看到
bash
进程增长从大约 1400 KiB 到 256 MiB当我要求它创建列表时{1..1000000}
。相反,考虑使用算术循环,
for (( i=1000000; i >= 1; --i )); do ...; done
或 POSIX 兼容循环,
i=1000000 while [ "$i" -ge 1 ]; do ...; i=$(( i - 1 )); done
这两种方法都不会在静态数字列表上循环,而是根据 测试值
$i
,1
如果测试成功则运行循环体,然后i
在每次迭代中递减变量 的值。每个数字的末尾都会有“额外的零”。这是因为您通过输出回车符将光标移回行首。这会移动光标,但不会清除该行,因此如果新数字的位数较少,则最后输出的数字的末尾仍然可见。
要解决这个问题,您可以尝试使用VT100 转义代码
\e[2K
用于在将光标移动到行首之前清除整行 ( ):for (( i=1000000; i >= 1; --i )); do printf '\e[2K\r%d' "$i" sleep 1 done printf '\n'
\e[1K
也将起作用,因为它会清除光标左侧的行区域。或者使用\r%d\e[0K
清除线路正确的输出数字后光标的位置。
答案2
您看到的问题是,您首先写入100
,然后99
最后1
从同一位置开始,但您在输出格式中仅指定了两位数字%2d
。
您尚未提供任何擦除指令,因此这就是您所看到的内容 - 但全部都在一行上
What # What
you # was
see # output
100 # 100
990 # 99
980 # 98
...
90 # 9
80 # 8
...
10 # 1
您应该使用三位数字进行格式化或添加空格后缀:
printf "\r%3d" $i # One option
printf "\r%2d " $i # Another option
答案3
如果您想用另一个字符串替换一个字符串,则需要两个字符串具有相同的大小(或更长的非打印字符(空格?))。
如果将已打印的内容替换123
为7
,则会得到723
或 ,127
具体取决于您是在开头还是在结尾打印。
要做到这一点(相同大小的字符串),您可以执行以下任一操作:
- 使用稳定大小的大括号扩展:
{000..123}
- 使用一个 printf 来填充整个空间:
printf '\r%5s' "$i"
- 打印一长串空格:
printf '\r%s ' "$i"
- 清除该行直至其末尾:
printf '\r%s\e[K' "$i"
- 清除整行然后打印值:
printf '\e[2K\r%s' "$i"
但使用 {1..1000000} 并不是最好的解决方案,因为它会生成一长串数字,需要将其保存在内存中,然后按空格进行划分,然后在循环中使用。 bash 中更好的解决方案是:
for(( i=1; i<1000; i++ )); do
printf '\r%5d' $i
sleep 0.01
done
echo