考虑这个文件:
#!/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
我需要添加一个新列:
- 计算行数,
- 发生后返回 1
/^TITLE/
, - 从文件底部开始向上移动,
基本上,结果应该是这样的:
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 的文件:
@Yarom
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
@oliv:
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
答案1
我设法编译了以下一行代码:
tac so_count.txt | awk 'BEGIN{x=0} {x++;{if ($1 != "TITLE") printf "%s,%s\n",$0,x;else if ($1 == "TITLE") {printf "%s,%s\n",$0,x;x=0}}}' | tac
我将进一步解释一下:
tac
- 反转线的顺序(反向猫)。awk
- 如果第一列没有TITLE
推进计数器,则TITLE
打印当前计数并重置回 0。tac
- 将其反转。
结果:
TITLE something,4
DATA some data,3
DATA some data,2
DATA some data,1
TITLE something else,2
DATA some other data,1
TITLE some more,4
DATA some other data,3
DATA some other data,2
DATA some other data,1
TITLE extra info,3
DATA some more data,2
DATA some more data,1
祝你好运!
答案2
使用 awk:
awk -v RS='TITLE ' -v FS='\n' '
{
for(i=NF-1;i>0;i--)
printf "%s,%d\n",$i,i;
printf RT
}' file
这依赖于设置的记录分隔符RS
和字段分隔符FS
来为计数器设置正确的起始值i
。
RT
唯一的语句打印与之关联的每个字段以及计数器和记录终止符RS
。
该解决方案的优点是仅解析文件一次,不需要将整个文件放入内存中。
答案3
例子.awk
#!/bin/awk -f
{ a[i++]=$0 } END {
while (i--) {
a[i]=a[i] "," ++j
if (a[i] ~ /^TITLE/) { j=0 }
}
for (i in a) { print a[i] }
}
例子
awk -f example.awk example.txt
输出
TITLE something,4
DATA some data,3
DATA some data,2
DATA some data,1
TITLE something else,2
DATA some other data,1
TITLE some more,4
DATA some other data,3
DATA some other data,2
DATA some other data,1
TITLE extra info,3
DATA some more data,2
DATA some more data,1
答案4
您可以将每个块视为一条记录,将每行视为一个字段 - 这样,您就可以减少每个块的计数,而无需反转文件或将多个块加载到内存中。
由于您的区块是由页眉而不是页脚划分的,因此需要一些技巧来处理第一条和最后一条记录。我能想到的最好的办法是:
awk -vRS='\n(TITLE|$)' -F'\n' -vOFS=, '
NR>1 {$1 = "TITLE" $1} # replace the RS that got stripped off
{for(i=1;i<=NF;i++) print $i, NF-i+1}
' example_file.txt
gawk
这在和中都应该有效mawk
。我怀疑它在低开销的 中运行速度会快得多mawk
;gawk
如果你将语言环境设置为 C/POSIX,速度可能会相当。LC_ALL=C awk '...'