【问题标题】:Matching third field in a CSV with pattern file in GNU Linux (AWK/SED/GREP)将 CSV 中的第三个字段与 GNU Linux (AWK/SED/GREP) 中的模式文件匹配
【发布时间】:2024-01-22 05:09:01
【问题描述】:

当第三个字段与模式文件中的模式匹配时,我需要打印 CSV 文件中的所有行。

我尝试了 grep,但没有成功,因为它匹配任何字段,而不仅仅是第三个。

grep -f FILE2 FILE1 > OUTPUT

文件1

dasdas,0,00567,1,lkjiou,85249
sadsad,1,52874,0,lkjiou,00567
asdasd,0,85249,1,lkjiou,52874
dasdas,1,48555,0,gfdkjh,06793
sadsad,0,98745,1,gfdkjh,45346
asdasd,1,56321,0,gfdkjh,47832

文件2

00567
98745
45486
54543
48349
96349
56485
19615
56496
39493

正确的输出

dasdas,0,00567,1,lkjiou,85249
sadsad,0,98745,1,gfdkjh,45346

错误的输出

dasdas,0,00567,1,lkjiou,85249
sadsad,1,52874,0,lkjiou,00567   <---- I don't want this to appear
sadsad,0,98745,1,gfdkjh,45346

我已经到处搜索并尝试了不同的公式。

编辑:感谢 Wintermute,我设法写了这样的东西:

csvquote file1.csv > file1.csv
awk -F '"' 'FNR == NR { patterns[$0] = 1; next } patterns[$6]' file2.csv file1.csv | csvquote -u > result.csv

Csvquote 帮助使用 AWK 解析 CSV 文件。

非常感谢大家,伟大的社区!

【问题讨论】:

    标签: linux bash awk sed grep


    【解决方案1】:

    使用 awk:

    awk -F, 'FNR == NR { patterns[$0] = 1; next } patterns[$3]' file2 file1
    

    它的工作原理如下:

    FNR == NR {           # when processing the first file (the pattern file)
      patterns[$0] = 1    # remember the patterns
      next                # and do nothing else
    }
    patterns[$3]          # after that, select lines whose third field
                          # has been seen in the patterns.
    

    【讨论】:

    • 不错的答案。你可以把它减少到awk -F, '{a[$0]++}a[$3]' file2 file
    • @JID 这可能会起作用,但我不喜欢在处理第二个文件(不包含模式)时向模式数组添加新条目,即使它们不太可能是匹配。如果该文件包含没有逗号的行,您可能会得到错误的结果。角落案例?是的。但没有理由冒险。
    • 鉴于 OP 的数据,我认为这不是问题,但足够公平:) 尽管我认为除非 file2 中有逗号分隔的字段,否则您仍然可以删除 next。我只是很挑剔,因为我不喜欢next
    • 第一个文件可以是管道吗?
    【解决方案2】:

    使用grepsed

    grep -f <( sed -e 's/^\|$/,/g' file2) file1
    dasdas,0,00567,1,lkjiou,85249
    sadsad,0,98745,1,gfdkjh,45346
    

    解释:

    我们在 file2 的开头和结尾插入一个逗号,但不更改文件,然后我们就像你已经在做的那样 grep。

    【讨论】:

      【解决方案3】:

      这可以是一个开始

      for i in $(cat FILE2);do cat FILE1|剪切 -d',' -f3|grep $i ;完成

      【讨论】:

      • 如果选中,您确定它会打印文件 1 的整行吗?
      【解决方案4】:
      sed 's#.*#/^[^,]*,[^,]*,&,/!d#' File2 >/tmp/File2.sed && sed -f /tmp/File2.sed FILE1;rm /tmp/File2.sed
      

      像 awk 这样的简单 sed 可以做到,但如果 awk 不可用,应该可以工作

      与 egrep 相同(对大文件有用)

      sed 's#.*#^[^,]*,[^,]*,&,#' File2 >/tmp/File2.egrep && egrep -f /tmp/File2.egrep FILE1;rm /tmp/File2.egrep
      

      【讨论】: