子集基于文件的一行并打印其他行,直到到达下一行

时间:2019-01-26 02:05:12

标签: bash perl

我有一个文本文件,其中包含多个类似于以下示例的条目:

public Completable getUserInfo() {
    return storeProvider.getToken()
            .flatMap(token -> webProvider.getUserInfo(token))
            .flatMapCompletable(userInfo -> storeProvider.saveUserInfo(userInfo));
}

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

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

#

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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,是专门为这些用例设计的)

答案 2 :(得分: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没有一行的原因。

答案 3 :(得分: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
$