考虑这个文件:
#!/usr/bin/env bash
cat > example_file.txt <<EOL
TITLE something
some data
some data
some data
TITLE something else
some other data
TITLE some more
some other data
some other data
some other data
TITLE extra info
some more data
some more data
EOL
我需要添加一个新列:
- 计算行数,
- 在发生 , 后返回
/^TITLE/
1 - 从文件的底部开始向上工作,
基本上,结果应该如下所示:
TITLE something,4
some data,3
some data,2
some data,1
TITLE something else,2
some other data,1
TITLE some more,4
some other data,3
some other data,2
some other data,1
TITLE extra info,3
some more data,2
some more data,1
PS你可以假设:
- 文件总是以匹配行开头
/^TITLE/
- 文件总是以不匹配的行结尾
/^TITLE/
- 没有连续的两行匹配
/^TITLE/
编辑:
到目前为止的结果
在一个 100MB 的文件上:
@亚罗姆
time tac trial.txt | awk 'BEGIN{x=0} {x++;{if ($1 !~/^pattern/) printf "%s,%s\n",$0,x;else if ($1 ~/^pattern/) {printf "%s,%s\n",$0,x;x=0}}}' | tac > trial2.txt
real 0m0,896s
@bac0n
time awk '{ a[i++]=$0 } END { while (i--) { a[i]=a[i] "," ++j; if (a[i] ~ /^pattern/) { j=0 } }; for (i=0; i<NR; i++) { print a[i] } }' trial.txt > trial2.txt
real 0m0,830s
@奥利夫:
time awk -v RS='^pattern' -v FS='\n' '
{
for(i=NF-1;i>0;i--)
printf "%s,%d\n",$i,i;
printf RT
}' trial.txt > trial2.txt
real 0m2,343s
@steeldriver
time awk -vRS='\n(^pattern|$)' -F'\n' -vOFS=, '
NR>1 {$1 = "^pattern" $1}
{for(i=1;i<=NF;i++) print $i, NF-i+1}
' trial.txt > trial2.txt
real 0m1,889s
使用 mawk 而不是 awk,我得到:
mawk: program limit exceeded: maximum number of fields size=32767
我设法编译了以下单行:
我再解释一下:
tac
- 颠倒行的顺序(反向猫)。awk
- 如果第一列没有TITLE
推进计数器,如果TITLE
打印当前计数并重置回 0。tac
- 反过来。结果:
祝你好运!
使用 awk:
这依赖于记录分隔符
RS
和字段分隔符FS
,它们设置为将正确的起始值设置为 counteri
。唯一的语句打印每个字段,其中包含与
RT
关联的计数器和记录终止符RS
。该解决方案的优点是只解析文件一次,并且不需要将整个文件放入内存中。
例子.awk
例子
输出
您可以将每个块视为一条记录,将每一行视为一个字段 - 这样,您可以在不反转文件或将多个块加载到内存中的情况下减少每个块的计数。
因为您的块是由页眉而不是页脚描述的,所以需要一些技巧来处理第一个和最后一个记录。我能想到的最好的是:
gawk
这在和中都应该有效mawk
。我怀疑它会在较低开销的情况下运行得更快mawk
;gawk
如果将语言环境设置为 C/POSIX,速度可能相当,即LC_ALL=C awk '...'