我有一个这种形式的数据文件
1 4
2 0
2 3
3 5
5 3
8 12
2 3
3 5
5 3
0 -1
2 4
33 3
该文件有 12 行,应解释为四个连续的数据块,每块 3 行。例如,第三个块是
2 3
3 5
5 3
如何在每个块中从 m 到 n 的块中提取从 i 到 j 的行,并将它们输出到 Linux 中的文件中?
例如,对于i=2
, j=3
, m=1
, n=3
,所需的结果应如下所示
2 0
2 3
5 3
8 12
3 5
5 3
谢谢。
答案1
以下awk
程序应该执行以下操作:
awk -v bs=3 -v i=2 -v j=3 -v m=1 -v n=3 '(FNR/bs>m-1) && (FNR/bs<=n) && ((FNR-1)%bs>=i-1) && ((FNR-1)%bs<j)' input.txt
这会将您的关键数据作为awk
变量导入到程序中:
- 块大小作为变量
bs
- 开始和结束块号作为变量
m
和n
- 开始和结束行号作为变量
i
和j
它使用这样awk
的逻辑:“规则”块之外的任何条件计算结果为true
(或非零)都指示awk
打印当前行。
打印基于自动变量FNR
,代表每个文件的行计数器。您的要求基本上相当于通过将数字FNR
除以块大小来识别块编号,并通过计算 的模数FNR
(为方便起见,我们使用FNR-1
从 0 开始)来识别块内的行,然后制定一个布尔表达式,该表达式仅true
对于您想要打印的那些行。
更新
可以通过尽可能避免耗时的操作来“加速”程序。为此,您可以按如下方式修改程序:
awk ... 'BEGIN{first=bs*(m-1)+1; last=bs*n}
FNR<first{next}
FNR>last{exit}
((FNR-1)%bs>=i-1) && ((FNR-1)%bs<j)' input.txt
这将首先确定要考虑的第一行和最后一行。
- 如果当前行号在第一个块的开头之前,我们立即跳到下一行,并且不执行任何计算和比较来“细粒度”检查是否打印。
- 同样,如果当前行号超过了要考虑的最后一个块,我们立即终止程序。
- 仅当我们位于“感兴趣区域”内时,才会执行算术运算来检查要打印的行。
这样,我们就可以将计算量保持在绝对最低限度。
如果您使用的是 GNU 变体awk
,并且已指定多个输入文件作为参数,请使用nextfile
而不是exit
跳到下一个文件而不是退出程序。
答案2
使用 GNU sed 和 awk 的替代解决方案:
# Split data into data-blocks
<infile sed '3~3G' |
# Only pass blocks m through n onwards
awk 'NR >= m && NR <= n' RS= ORS='\n\n' m=1 n=3 |
# Only print lines i through j within each block
awk '{ for (x=i ; x<=j; x++) print $x }' RS= FS='\n' i=2 j=3
答案3
使用 GNU sed 和单独的流选项 (-s) 将命令行中的多个文件作为单独的文件进行处理。
i=2 j=3 m=1 n=3 G=3
split -l "$G" file
printf '%s\n' x?* |
sed -e "$m,$n!d;${n}q" |
xargs sed -s "$i,$j!d"
答案4
使用 Raku(以前称为 Perl_6)
raku -e '.join("\n").put for lines.rotor(3)[0..2].map(*.[1..2]);'
输入示例:
1 4
2 0
2 3
3 5
5 3
8 12
2 3
3 5
5 3
0 -1
2 4
33 3
示例输出:
2 0
2 3
5 3
8 12
3 5
5 3
上面是用 Raku(Perl 编程语言家族的成员)编写的解决方案。简而言之,lines
被读入(懒惰地)和rotor
-ed (即分组)在一起,3
每个行都精确分组(末尾不完整的组将随上面的代码一起删除,如果您希望返回部分组,请添加正确的“副词”选项,像这样rotor(3, :partial)
:)。
前 3 组每三行被保留(使用[0..2]
索引构造),并map(*.[1..2])
在这三组内执行映射以仅返回第二个和第三个元素(Perl 系列语言如 Raku 从零开始索引)。
上面的代码返回所需的结果,但是如果程序员愿意,结果可以按行/引用返回,如下所示:
raku -e '.raku.put for lines.rotor(3)[0..2].map(*.[1..2]);' file
("2 0", "2 3")
("5 3", "8 12")
("3 5", "5 3")