【问题标题】:Shell script numbering lines in a file文件中的 Shell 脚本编号行
【发布时间】:2010-09-25 22:16:23
【问题描述】:

我需要找到一种使用 awk 和 sed 等工具以特定方式对文件中的行进行编号的更快方法。我需要以这种方式对每行的第一个字符进行编号:1,2,3,1,2,3,1,2,3 等。

例如,如果输入是这样的:

line 1
line 2
line 3
line 4
line 5
line 6
line 7

输出需要如下所示:

1line 1
2line 2
3line 3
1line 4
2line 5
3line 6
1line 7

这是我所拥有的一部分。 $lines 是数据文件中的行数除以 3。因此,对于 21000 行的文件,我处理此循环 7000 次。

export i=0
while [ $i -le $lines ]
do
    export start=`expr $i \* 3 + 1`
    export end=`expr $start + 2`
    awk NR==$start,NR==$end $1 | awk '{printf("%d%s\n", NR,$0)}' >> data.out
    export i=`expr $i + 1`
done

基本上,这一次抓取 3 行,对它们进行编号,然后添加到输出文件中。它很慢......然后一些!我不知道另一种更快的方法可以做到这一点...有什么想法吗?

【问题讨论】:

    标签: shell sed awk


    【解决方案1】:

    想到 Perl:

    perl -pe '$_ = (($.-1)%3)+1 . $_'
    

    应该可以。毫无疑问,有一个 awk 等价物。基本上,((line# - 1) MOD 3) + 1

    【讨论】:

    • perl -e 'printf "%d%s", (($.-1)%3)+1, $_' :-D
    • 乔纳森:为什么要使用 printf?似乎 derobert 的回答更直截了当。
    • 因为使用 printf() 不会修改 $_;甚至可能会节省时间,尽管担心还不够。
    • 如果要优化,print 可能会比 printf 快。
    【解决方案2】:

    试试nl 命令。

    请参阅https://linux.die.net/man/1/nl(或其他指向当您在 Google 搜索“man nl”时出现的文档的链接,或在 shell 提示符下运行 man nl 时出现的文本版本)。

    nl 实用程序从 命名文件或标准输入 if 文件参数被省略,适用 可配置的行号过滤器 操作并将结果写入 标准输出。

    编辑:不,这是错误的,我很抱歉。 nl 命令没有在每n 行重新开始编号的选项,它只有在找到模式后重新开始编号的选项。我会将这个答案设为社区 wiki 答案,因为它可能有助于某人了解 nl

    【讨论】:

    • Love Unix 工具尝试回答脚本问题。还有“cat -n”作为一个不太完善的 nl。对于 sed 的反思型学生,可以修改以下内容以获得所需的确切答案:gnu.org/software/sed/manual/sed.html#cat-_002dn
    • @jaredor 你应该添加它作为答案!
    • rt.com 链接已失效。
    【解决方案3】:
    awk '{printf "%d%s\n", ((NR-1) % 3) + 1, $0;}' "$@"
    

    【讨论】:

      【解决方案4】:

      这很慢,因为您一遍又一遍地阅读相同的行。此外,您正在启动一个awk 进程,只是为了将其关闭并启动另一个进程。最好一次性完成所有事情:

      awk '{print ((NR-1)%3)+1 $0}' $1 > data.out
      

      如果您希望在数字后有一个空格:

      awk '{print ((NR-1)%3)+1, $0}' $1 > data.out
      

      【讨论】:

        【解决方案5】:

        Python

        import sys
        for count, line in enumerate(sys.stdin):
            stdout.write( "%d%s" % ( 1+(count % 3), line )
        

        【讨论】:

          【解决方案6】:

          这应该可以解决问题。 $_ 将打印整行。

          awk '{print ((NR-1)%3+1) $_}' < input
          1line 1
          2line 2
          3line 3
          1line 4
          2line 5
          3line 6
          1line 7
          
          # cat input 
            line 1
            line 2
            line 3
            line 4
            line 5
            line 6
            line 7
          

          【讨论】:

            【解决方案7】:

            你不需要为此离开 bash:

            i=0; while read; do echo "$((i++ % 3 + 1)) $REPLY"; done < input
            

            【讨论】:

            • 如果输入包含前导空格或反斜杠,这将不起作用。
            【解决方案8】:

            这可能对你有用:

             sed 's/^/1/;n;s/^/2/;n;s/^/3/' input
            

            【讨论】:

              【解决方案9】:

              另一种方法是使用 grep 并匹配所有内容。例如这将枚举文件:

              grep -n '.*' <<< `ls -1`
              

              输出将是:

              1:file.a
              2:file.b
              3:file.c
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-08-10
                • 2011-09-08
                • 2018-09-25
                • 2014-02-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-05-19
                相关资源
                最近更新 更多