如何解决使用bash将行号添加到最终的非空行
是否可以将行号添加到文件中,但是只能从最后一个空行之后的行开始?例如
aaa
bbb
ccc
ddd
eee
将成为
aaa
bbb
ccc
1. ddd
2. eee
因为ddd
行是最后一个空白行之后的第一行。
现在,我正在使用vim逐个文件执行此操作(通过选择行并执行快速命令),但是我需要运行1,000个文件,因此我不想这样做单独手动操作,但无法解决该问题。
解决方法
您可以使用awk
和三项规则(包括END
规则)对最后一行进行编号,例如
awk '
NF > 0 { a[++n]=$0 }
NF == 0 { for(i=1; i<=n; i++) print a[i]; print""; n=0 }
END { for(i=1; i<=n; i++) printf "%d. %s\n",i,a[i]}
' file
说明
- 对于第一个规则
NF > 0
,如果至少有一个字段(行非空),则将该行存储在数组a
和预递增计数器n
中(到与awk
1 to NF
索引保持一致) - 对于第二条规则
NF == 0
,如果该行为空,则输出您在a
中存储的内容,然后输出一个空行并将n
重置为零; - 最后,在
END
规则中,编号并输出存储在a
中的所有行。
使用/输出示例
$ awk '
> NF > 0 { a[++n]=$0 }
> NF == 0 { for(i=1; i<=n; i++) print a[i]; print""; n=0 }
> END { for(i=1; i<=n; i++) printf "%d. %s\n",a[i]}
> ' file
aaa
bbb
ccc
1. ddd
2. eee
,
这是awk
的解决方案。
awk '!NF{x=NR} {r[NR]=$0}
END {for (i=1;i<=NR;i++) print (i>x? (++n)". "r[i]: r[i])}' file
我们将行存储到数组中。在END
,x
将是最后一个空白数字行,因此我们为大于x
的行号打印编号。
这是两次通过的版本,不需要将整个文件读入内存。如果它是一个 large 文件,则可能要考虑内存:
awk ' NR==FNR {if (/^[ \t]*$/) ll=FNR; next}
FNR>ll {c++}
{printf "%s%s\n",(c ? c "." OFS : ""),$0}' file file
打印:
aaa
bbb
ccc
1. ddd
2. eee
使用sed
和tail
,您可以像这样计算最后一个空白行:
$ sed -n '/^[[:blank:]]*$/=' file | tail -1
5
您还可以用来为awk
设置变量:
awk -v ll=$(sed -n '/^[[:blank:]]*$/=' file | tail -1) '
FNR>ll {c++}
{printf "%s%s\n",$0}' file
在任何情况下,您只能执行以下两项操作之一:将整个文件保存在内存中,并在全部读取或两次读取后进行打印。在大多数情况下,最好读取两次,因为它不会影响内存,并且通常速度也一样快(因为大多数操作系统都会缓存文件。)
只是比较读取整个文件和读取两次的一些时间,所以考虑一个100行的文件(可能太快而无法准确测量):
$ awk 'BEGIN {for (i=1; i<=101; i++) print i%3 ? i : ""}' >/tmp/file
现在,使用全部读取与两次读取解决方案:
time awk -v ll=$(sed -n '/^[[:blank:]]*$/=' file | tail -1) '
FNR>ll {c++}
{printf "%s%s\n",$0}' file > /dev/null
time awk '
NF > 0 { a[++n]=$0 }
NF == 0 { for(i=1; i<=n; i++) print a[i]; print""; n=0 }
END { for(i=1; i<=n; i++) printf "%d. %s\n",a[i]}
' file > /dev/null
time awk ' NR==FNR {if (/^[ \t]*$/) ll=FNR; next}
FNR>ll {c++}
{printf "%s%s\n",$0}' file file > /dev/null
打印:
real 0m0.012s
user 0m0.004s
sys 0m0.007s
real 0m0.007s
user 0m0.003s
sys 0m0.003s
real 0m0.007s
user 0m0.003s
sys 0m0.003s
现在尝试使用100,001行:
awk 'BEGIN { for (i=1; i<=100001; i++) print i%3 ? i : ""}' >/tmp/file
time awk -v ll=$(sed -n '/^[[:blank:]]*$/=' file | tail -1) '
FNR>ll {c++}
{printf "%s%s\n",$0}' file file > /dev/null
时间:
real 0m0.081s
user 0m0.079s
sys 0m0.007s
real 0m0.047s
user 0m0.042s
sys 0m0.004s
real 0m0.058s
user 0m0.052s
sys 0m0.004s
现在10,000,001行:
awk 'BEGIN { for (i=1; i<=10000001; i++) print i%3 ? i : ""}' >/tmp/file
time awk -v ll=$(sed -n '/^[[:blank:]]*$/=' file | tail -1) '
FNR>ll {c++}
{printf "%s%s\n",$0}' file file > /dev/null
时间:
real 0m6.766s
user 0m7.671s
sys 0m0.063s
real 0m3.950s
user 0m3.921s
sys 0m0.026s
real 0m4.801s
user 0m4.754s
sys 0m0.041s
令人惊讶的是,较小的文件两次读取它的速度稍快,而较大的文件将其保存在内存中的速度稍快。这是在具有64GB RAM和SSD的计算机上。较小的内存或较慢的硬盘驱动器会改变这种情况。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。