仅 Grep 数据 (-o) 和第一列

仅 Grep 数据 (-o) 和第一列

样本数据

wolf@linux:~$ cat data.csv 
A,4.4.4.4,4.4.4.5,4.4.4.6,3.3.3.3,3.3.3.4
B,1.1.1.1,1.1.1.1,1.1.1.2,1.1.1.3,3.3.3.3
C,1.1.1.1,1.1.1.1,1.1.1.1,1.1.1.1,1.1.1.1
D,2.2.2.1,2.2.2.1,2.2.2.2,2.2.2.3,2.2.2.4
wolf@linux:~$ 

该样本中有一些重复的数据。例如,有两个3.3.3.3位于 A 行和 B 行。

wolf@linux:~$ egrep 3.3.3.3 data.csv 
A,4.4.4.4,4.4.4.5,4.4.4.6,3.3.3.3,3.3.3.4
B,1.1.1.1,1.1.1.1,1.1.1.2,1.1.1.3,3.3.3.3
wolf@linux:~$ 

现在我只对第一列A,B,C,D以及相关数据感兴趣。

这是我需要找到的 4 个数据。

2.2.2.3
3.3.3.3
4.4.4.4
5.5.5.5

所以,我在egrep中使用|and-o

wolf@linux:~$ egrep '2.2.2.3|3.3.3.3|4.4.4.4|5.5.5.5' data.csv
A,4.4.4.4,4.4.4.5,4.4.4.6,3.3.3.3,3.3.3.4
B,1.1.1.1,1.1.1.1,1.1.1.2,1.1.1.3,3.3.3.3
D,2.2.2.1,2.2.2.1,2.2.2.2,2.2.2.3,2.2.2.4
wolf@linux:~$ 

输出很好,但是里面的数据太多了。我只想要相关数据和第一列。

所以,这是另一个尝试-o

wolf@linux:~$ egrep -o '2.2.2.3|3.3.3.3|4.4.4.4|5.5.5.5' data.csv
4.4.4.4
3.3.3.3
3,3.3.3
2.2.2.3
wolf@linux:~$ 

现在的问题是我无法得到第一列(A/B/C/D

下次尝试

wolf@linux:~$ egrep '2.2.2.3|3.3.3.3|4.4.4.4|5.5.5.5' data.csv | cut -d , -f 1
A
B
D
wolf@linux:~$

我得到了第一列,但没有得到数据。通过查看输出,我不知道A同时代表3.3.3.3和 ,4.4.4.4因为它没有显示在输出上。

这并不是我真正想要的输出。我现在的想法是这样的

所需输出

输入

2.2.2.3
3.3.3.3
4.4.4.4
5.5.5.5

输出

D       2.2.2.3   
A,B     3.3.3.3
A       4.4.4.4
-       5.5.5.5

不幸的是,我现在想不出解决方案。请帮忙

答案1

$ cat script.awk
NR == FNR {
  a[$0]
  next
}

{
  for (i = 2; i <= NF; i++) {
    for (k in a) {
      if ($i == k) {
        a[k] = a[k] ? a[k] "," $1 : $1
      }
    }
  }
}

END {
  for (k in a) {
    print a[k] "\t" k
  }
}

运行它作为:

$ cat search.txt
2.2.2.3
3.3.3.3
4.4.4.4
5.5.5.5

$ awk -F, -f script.awk search.txt data.csv
A,B     3.3.3.3
D       2.2.2.3
A       4.4.4.4
        5.5.5.5

答案2

首先请注意,正则表达式不仅2.2.2.3会匹配(与匹配任何字符的正则表达式运算符一样)也会匹配内部。2.2.2.3212.243.22.2.2.36

在这里,我会使用perl

<data.csv perl -F, -lane '
  BEGIN {for (@l = qw{2.2.2.3 3.3.3.3 4.4.4.4 5.5.5.5}) {$v{$_} = []}}
  for (grep $v{$_}, @F[1..$#F]) {push @{$v{$_}}, $F[0]}
  END {for (@l) {print(join(",", @{$v{$_}}) || "-", "\t$_")}}'

这使:

D       2.2.2.3
A,B     3.3.3.3
A       4.4.4.4
-       5.5.5.5

要回答主题中的问题,为了grep -o-o顺便说一句,作为非标准扩展)在输出行上报告输入行的多个部分,您可以使用pcregrep

<data.csv pcregrep -o1 -o2 --om-separator=$'\t' \
  '^([^,]*).*?,(2\.2\.2\.3|3\.3\.3\.3|4\.4\.4\.4|5\.5\.5\.5)(,|$)'

但这只能报告每行一个单词。这里给出:

A       4.4.4.4
B       3.3.3.3
D       2.2.2.3

使用grep -Po,假设grep使用类似 perl 的正则表达式支持构建(顺便说一句,在大多数实现中使用 PCRE 进行类似 perl 的正则表达式匹配,因此它与 相同pcregrep -o),您可以这样做:

$ grep -Po '^[^,]*+(?=.*?(?1))|((?<![^,])(2\.2\.2\.3|3\.3\.3\.3|4\.4\.4\.4|5\.5\.5\.5)(?![^,]))' data.csv
A
4.4.4.4
3.3.3.3
B
3.3.3.3
D
2.2.2.3

这是first-field-provided-there-is-matching-data|matching-data.

这里provided-there-is-matching-data是用(?=...)正向前瞻运算符实现的,这意味着前提是接下来的内容匹配...,这里(?1),正则表达式存储在第一个捕获组中,因此匹配数据后面有任意数量的字符 ( .*?)。

对于匹配数据,我们使用(2\.2\.2\.3|3\.3\.3\.3|4\.4\.4\.4|5\.5\.5\.5)s.进行转义,但使用一些否定环视运算符 ((?<!...)(?!...)) 表示:前提是之前和之后的内容是不是字符以外的字符,确保它们与 csv 字段的内容完全匹配。

答案3

一种简单的方法如下。要查找的键在名为keys.txt 的文件中每行列出一个键,并放在perl 命令的标准输入上,同时要搜索的数据作为参数放置。

$ < keys.txt \
perl -F, -lane '
  $.==1 && chomp(@keys = <STDIN>);
  $_ .= "$F[0]," for @h{
    grep { my $k = $_; grep(($_ eq $k), @F)} @keys;
  }}{$, = "\t";
  print((($h{$_} //= "-") =~ s/,$//r), $_) for @keys;
' data.csv
D   2.2.2.3
A,B 3.3.3.3
A   4.4.4.4
-   5.5.5.5

答案4

使用米勒(https://github.com/johnkerl/miller)并运行

mlr --c2t -N reshape -r "^[^1]$" -o item,value \
then filter '$value=~"(2\.2\.2\.3|3\.3\.3\.3|4\.4\.4\.4|5\.5\.5\.5)"' \
then cut -x -f item \
then nest --implode --values --across-records -f 1 --nested-fs "," \
then reorder -f value data.csv >output

你将会拥有

4.4.4.4 A
3.3.3.3 A,B
2.2.2.3 D

然后使用您的过滤器列表

$ cat list
8.8.8.8
2.2.2.3
3.3.3.3
4.4.4.4
5.5.5.5

你可以跑

mlr --tsv -N join --ul -j 1 -f list then unsparsify output

具有

4.4.4.4 A
3.3.3.3 A,B
2.2.2.3 D
8.8.8.8
5.5.5.5

相关内容