【问题标题】:How to zero pad a sequence of integers in bash so that all have the same width?如何在bash中对整数序列进行零填充,以使它们具有相同的宽度?
【发布时间】:2012-02-06 01:33:46
【问题描述】:

我需要循环一些值,

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

对于$first$last,我需要它是固定长度5。因此,如果输入是1,我需要在前面添加零,使其变为00001。例如,它会循环到 99999,但长度必须为 5。

例如:000020004200212012312 等等。

知道我该怎么做吗?

【问题讨论】:

标签: bash numbers padding


【解决方案1】:

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

#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 上也很有效,因为分叉是一项非常繁重的操作。我有一个 110000 个文件列表,使用 printf "%06d" $NUM 花了 1 多分钟,上面的解决方案运行了大约 1 秒。

【讨论】:

  • 不幸的是,我建议的编辑将循环的最后一行 TEMP=$(( TEMP + 1 )) 更改为 CNT=$(( CNT + 1 )) 被拒绝,尽管增加 TEMP 而不是 CNT 没有意义! ...因为TEMP 在循环开始时被0000001 覆盖,你将得到一个无限循环。
  • 除此之外,这个答案(尤其是echo ${TEMP:(-6)})非常好! - 虽然there are also slightly different variants 可能更适合不同的用例。
【解决方案2】:

如果您只是在用零填充数字以达到固定长度后,只需添加最接近的 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 版本 3.2.48 上测试

【讨论】:

    【解决方案3】:

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

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

    3.) “回显”每个数字。数字存储在变量“i”中,使用“$”访问。

    优点:这段代码很干净。

    缺点:“seq”并非所有 Linux 系统都原生(据我了解)

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

    【讨论】:

      【解决方案4】:

      其他方式:

      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} 
      
      }
      

      【讨论】:

      • 如果数字不得超过 3 位,我会推荐askubuntu.com/a/1257316/354350 中的temp_num 的第一个变体。 || 虽然我个人更喜欢echo ${zeroos:0:-${#num}}${num},就像“注 1”中提到的那样。
      【解决方案5】:

      这也可以:

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

      【讨论】:

        【解决方案6】:

        如果要 N 位,加 10^N 并删除第一位。

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

        输出:

        01
        02
        03
        04
        05
        

        【讨论】:

          【解决方案7】:

          我用比我需要的更多的数字(零)填充输出,然后使用 tail 只使用我正在寻找的数字的数量。请注意,您必须在尾部使用“6”才能获得最后五位数字:)

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

          【讨论】:

          • 如果您想在 tail 的 -c 参数中使用正确数量的位置,您可以使用 'echo -n 00000$i' 因为这会阻止它输出作为字符之一的换行符tail 正在返回,因此它需要在这个答案中更高。根据您当时的操作,换行符(如果留下)可能会影响结果。
          • 使用外部进程修剪循环中的变量是相当低效的。您可以改用 shell 的 parameter expansion 功能。在 Bash 中有一种按索引提取特定子字符串的工具,或者您可以使用前缀和后缀替换与所需宽度匹配的模式,尽管它需要一些来回。
          【解决方案8】:

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

          seq -w 1 10
          

          生产

          01
          02
          03
          04
          05
          06
          07
          08
          09
          10
          

          【讨论】:

          • 这显然是正确的答案。为什么点赞这么少? ?
          • 简单,因为填充取决于您想要达到的最大数量。如果这是一个你永远不知道你最终会得到多少个零的参数
          • 这并没有给出指定的固定长度,只是给出了所有相同长度的结果。
          • 你也可以seq -w 001 009强制长度为3。
          • 在 macOS 中安装的新 seq 无法执行 seq -w 001 009,所以你很幸运它对你有用
          【解决方案9】:

          你可以做的更简单

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

          【讨论】:

          • 这适用于 Bash 版本 4.1.2 (CentOS 6) 但在版本 3.2.25 (CentOS 5) 中失败。我同意这是更美观的方式!
          • 有效,但在我的 bash 中没有给出零填充字符串
          • 在 Mac (Bash 4.4) 上,这不会填充数字。在 CentOS 和 SuSE 上,它运行良好!
          • 这可以在 macOS 上使用 Bash 4.4.23(1)-release
          • bash 令人惊讶,这是个好方法
          【解决方案10】:

          像这样使用 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 版本上不可用

          【讨论】:

          • 我们可以使用awk's BEGIN 语句,这样我们就不必使用heredoc 赋值。
          • @JaypalSingh:谢谢伙计,这很好。更新了我的答案。
          【解决方案11】:

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

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

          将产生以下输出:

          00010
          00011
          00012
          00013
          00014
          00015
          

          更一般地说,bash 具有 printf 作为内置功能,因此您可以用零填充输出,如下所示:

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

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

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

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

          【讨论】:

          • %05g 而不是 %05d 为我修复了它。 "00026" 给了我 "00022"。谢谢!
          • 很好,全面的答案。一个小的更正:严格来说,seq 支持格式字符的 子集printf 支持(并且该子集包括 g,但不包括 d)。字符dg 的行为有细微的不同,d 将带有0 前缀的数字字符串解释为八进制 数字并将它们转换为十进制,而g 将它们视为十进制. (@EdManet:这就是为什么 '00026' 变成了 d 的 '00022')。另一件值得一提的事情:seq -w 会根据生成的最宽数字对输出数字进行自动补零。
          • 这帮助我生成了十六进制字符列表。 for (( i = 0; i &lt;= 0xffffffff; i++ )) do printf "%08x\n" $i ; done &gt;&gt; hex.txt 生成了一个 8 个字符的十六进制列表。谢谢。
          • seq --help: "FORMAT 必须适合打印一个'double' 类型的参数;如果FIRST、INCREMENT 和LAST 都是具有最大精度PREC 的定点十进制数,则默认为%.PRECf , 否则为 %g。”可能的conversion specifiersefgaEFGA
          • 这比 seq 提供的-w 选项慢得多。并且因为它通过 printf 传递数字,如果你没有运行 GNU 版本(即运行 mac 本机版本),你最终会得到更大数字的科学记数法(大约任何大于 6 位的整数都将在 x. xxxxxxe+0y 格式)
          【解决方案12】:

          使用printf非常简单

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

          【讨论】:

            【解决方案13】:

            将 printf 与 "%05d" 一起使用,例如

            printf "%05d" 1
            

            【讨论】:

              猜你喜欢
              • 2021-07-16
              • 1970-01-01
              • 1970-01-01
              • 2013-02-26
              • 2019-04-16
              • 1970-01-01
              • 1970-01-01
              • 2017-07-20
              • 2017-09-09
              相关资源
              最近更新 更多