对文件中的特定列使用 awk 和 inverse grep

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

假设制表符分隔的文件作为输入文件 1 (

$IN1
):

$ cat input1.tsv
HEAD1   HEAD2   HEAD3   HEAD4   HEAD5   HEAD6
Qux ZX_999876   Bar Foo MN111111    Quux
Foo AB_123456   Bar Baz CD789123    Qux
Bar AC_456321   Baz Qux GF333444    Foo
Foo CD789123    Qux Baz GH987124    Qux

进一步假设一个 csv 分隔的文件作为输入文件 2 (

$IN2
):

$ cat input2.csv
AB_123456,CD789123
ZX_999876,MN111111

输入文件2指定需要删除输入文件1的哪些行。具体来说,如果输入文件 2 的第 1 列条目等于输入文件 1 的第 2 列条目,则输入文件 1 中输入文件 2 的第 2 列条目等于输入文件 1 的第 2 列条目的所有行为将被删除。

所需输出:

$ cat input1_filtered.tsv
HEAD1   HEAD2   HEAD3   HEAD4   HEAD5   HEAD6
Qux ZX_999876   Bar Foo MN111111    Quux
Foo AB_123456   Bar Baz CD789123    Qux
Bar AC_456321   Baz Qux GF333444    Foo

我希望通过 Bash 实现所需的输出。 我的(到目前为止还不够)尝试:

while IFS=, read -r CL1 CL2
do
    if awk -F"\t" '$2=="$CL1"' $IN1
    then
        grep -vPw "(?<=\t)$CL2" $IN1 > tmp.txt
        mv tmp.txt $IN1
    fi
done < $IN2
bash awk grep multiple-columns
1个回答
0
投票

这专门使用了 GNU awk:

  • 处理 input2.csv,存储映射
  • 处理 input1.tsv,确定 input2.csv 的 col1 是否存在
  • 再次处理 input1.tsv,过滤掉不需要的记录
gawk '
    BEGINFILE   { FS = ARGIND == 1 ? "," : "\t" }
    ARGIND == 1 { is_present[$1] = $2; next }
    ARGIND == 2 { if ($2 in is_present) del[is_present[$2]] = 1; next }
    !($2 in del)
' input2.csv input1.tsv input1.tsv

输出

HEAD1   HEAD2   HEAD3   HEAD4   HEAD5   HEAD6
Qux ZX_999876   Bar Foo MN111111    Quux
Foo AB_123456   Bar Baz CD789123    Qux
Bar AC_456321   Baz Qux GF333444    Foo
© www.soinside.com 2019 - 2024. All rights reserved.