如何打印行号但在空行处重置行计数器?

如何打印行号但在空行处重置行计数器?

我有一个 file.txt 包含:

this is the first
second line
not last line

fourth but first
second in list
seventh in file
seventh with nl

通常我会像这样将其通过cat管道传输:|nl

$> cat file.txt | nl
1  this is the first
2  second line
3  not last line

4  fourth but first
5  second in list
6  seventh in file
7  seventh with nl 

但是当遇到空行时我需要重置行号,如下所示:

$> alias_or_function file.txt
1  this is the first
2  second line
3  not last line

1  fourth but first
2  second in list
3  seventh in file
4  seventh with nl 

我如何使用我的快速函数或别名来做到这一点~/.zshrc

答案1

您可以将空白行替换为\:\:nl页面正文的开始:

<your-file sed 's/^[[:space:]]*$/\\:\\:/' | nl

所以作为一个函数:

number-lines-of-paragraphs() {
  sed -e 's/^[[:space:]]*$/\\:\\:/' -- "$@" | nl
}

(请注意,如果 , ,也出现在输入中,则将其nl理解为页眉/正文/页脚分隔符,这就是为什么您通常不能使用它向任意文本添加行号)。\:\:\:\:\:\:nl

您还可以获得相同的输出格式,而无需使用以下警告awk

awk 'NF {printf "%6u\t%s\n", FNR, $0; next}; {FNR = 0; print}'

或者其他人在这里发布的一些变体。

上面的数字是左加垫最多 6 个字符,后跟一个 TAB 字符,就像默认nl输出格式一样(其中%6u\t%s\n相当于nl的 default -s $'\t' -n rn -w 6),但您当然可以根据自己的喜好调整该格式。

但是现在,要使其成为一个以任意文件名作为参数的函数,您就会遇到awk自身的警告,即它会阻塞包含字符的文件名,=因为这些字符被解释为 awk 变量赋值(至少如果第一个左边的内容=看起来像一个有效的 awk 变量名)。可以使用gawk以下方法解决此问题:

number-lines-of-paragraphs() {
  gawk -e '
    NF {printf "%6u\t%s\n", FNR, $0; next}
    {FNR = 0; print}' -E /dev/null "$@"
}

请注意,如果该函数传递给多个文件,则行号将在每个文件的开头重置。如果您希望将所有文件的内容作为一个流来像方法中那样作为一个整体进行编号sed | nl,请替换FNRNR上面的内容。

在任何情况下,sedgawk都会理解为 stdin,而不是当前目录中-调用的文件(用于解决它)。-./-

答案2

如果您愿意使用awk

$ cat nl.awk
{
   if ( $0 == "" ) {
      count = 0
      print
   } else
      print ++count, $0
}

输出:

$ awk -f nl.awk infile
1 this is the first
2 second line
3 not last line

1 fourth but first
2 second in list
3 seventh in file
4 seventh with nl

答案3

使用 awk:

awk '{ c=NF?++c:"" } {print c,$0}' file

它的意思是:

  • 如果有任何字段NF?(任何(非空格)字符),c则以递增++c
  • 如果没有字段(没有字符),则将行计数器清空。
  • 打印计数器,后跟实际行print c,$0

遗憾的是,这个简短的解决方案将空行转换为包含空格的行(或者实际上,转换为 OFS 的值)。如果这是一个问题,那么使用这个(类似的)解决方案:

awk 'NF{$0=++c" "$0}!NF{c=0}1' file

在此解决方案中没有理由将空行更改为\:\:

相关内容