基于子行文件的一行和打印其他行直到它到达下一行

问题描述 投票:1回答:4

我有一个文本文件,其中包含多个条目,如下所示:

# 2018 11 21 17 47 37.708756 -34.390213 116.803673 2.6972 0.442474 3.324627 2.840390 0.885880 890
LM01 0.836408 1.00 P
LM01 1.035398 1.00 S
LM03 3.987074 1.00 S
# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S

我需要提出一种方法,最好是在Bash或Perl中,用#读取行,基于第8列(纬度)排列的子集,如果条件满足,则打印其余行(例如LM。 ..)直到它与#到达下一行。例如,我只想打印第8列<-34.4的“条目”,并包含该条目的LM *行。

我可以拿出代码来读取每个#线,但我不确定如何编程“如果满足条件,打印LM线直到你到达下一个#行”。预期的产出是:

# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S
bash perl
4个回答
2
投票

gawk记录分隔符,perl应该有类似的...

$ awk -v RS='(^|\n)#' '$7<-34.4{printf "%s", rt $0} {rt=RT}' file

# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S

请注意,您需要<,因为该标志是否定的。由于我们使用#作为记录分隔符,因此字段数减少一个。

我们将记录分隔符定义为前导#或后面的新行。通常RS在记录之间,但在这里它是领先的记录。这就是为什么我们捕获匹配的记录分隔符RT并分配给(下一个)记录中使用的变量。 RT也包括新线,这就是为什么printf没有。


5
投票

如果标志打开,则在不以#打印的行上打印,否则根据条件设置标志(和打印)

perl -wlnE'
    if (/^\s*[^#]/) { say if $y } elsif ((split)[7] < -34.4) { $y=1, say }
' file

使用file中提供的样本输入,可以打印预期的输出。

标志-lnE可以是-ne,代码中使用print而不是say-w仅用于警告,通常在单行中省略(我总是使用它)。见Command switches in perlrun


3
投票
perl -lane '$matches = ($F[7] < -34.4); print if ($matches .. (/^#/ and not $matches)) and ($matches or not /^#/)'

这有点牵扯。你可以让$matches成为你想要的# ...线上的任何表达。 ($matches .. (/^#/ and not $matches))匹配所有标题行,包括下一个(可能不匹配)标题,然后and ($matches or not /^#/)排除任何不匹配的标题。

..是专为这些用例而设计的Range Operator


1
投票

另一个Perl单线

  perl -0777 -ne ' while( /(^#.+?)(?=^#|\Z)/gsm ) { print $1 if (split(" ",$1))[7] < -34.4 } '

输入

$ cat geeb.txt
# 2018 11 21 17 47 37.708756 -34.390213 116.803673 2.6972 0.442474 3.324627 2.840390 0.885880 890
LM01 0.836408 1.00 P
LM01 1.035398 1.00 S
LM03 3.987074 1.00 S
# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S
$ perl -0777 -ne ' while( /(^#.+?)(?=^#|\Z)/gsm ) { print $1 if (split(" ",$1))[7] < -34.4 } ' geeb.txt
# 2018 11 22 11 58 25.550581 -34.439400 116.750832 2.8513 0.288144 3.306790 2.576028 0.771026 891
LM01 1.664419 1.00 P
LM01 2.471786 1.00 S
LM03 3.536432 1.00 P
# 2018 11 22 14 38 7.190175 -34.447819 116.788727 3.1661 0.577347 2.063253 2.132511 0.608057 892
LM01 1.629825 1.00 P
LM02 3.059825 1.00 P
LM03 3.284825 1.00 P
LM01 2.378885 1.00 S
$
© www.soinside.com 2019 - 2024. All rights reserved.