0

我有一个姓名和 ID 列表(50 个条目)

cat input.txt

name    ID
Mike    2000
Mike    20003
Mike    20002

还有一个巨大的压缩文件(13GB)

zcat clients.gz

name    ID  comment
Mike    2000    foo
Mike    20002   bar
Josh    2000    cake
Josh    20002   _

我的预期输出是

NR  name    ID  comment
1    Mike   2000    foo
3    Mike   20002   bar

每个$1"\t"$2clients.gz 都是一个唯一标识符。input.txt中可能缺少一些条目clients.gz。因此,我想将 NR 列添加到我的输出中以找出丢失的内容。我想使用 zgrep。awk 需要很长时间(因为我必须zcat解压缩我假设的压缩文件?)

我知道那zgrep 'Mike\t2000'行不通。我想我可以用 awk FNR 解决 NR 问题。

到目前为止,我有:

awk -v q="'" 
'
NR > 1 {
print "zcat clients.gz | zgrep -w $" q$0q
}' input.txt |
bash > subset.txt
4

3 回答 3

1

使用 GNU awk 和 bash:

awk 'BEGIN{FS=OFS="\t"} 
     # process input.txt
     NR==FNR{
       a[$1,$2]=$1 FS $2
       line[$1,$2]=NR-1
       next
     }
     # process <(zcat clients.gz)
     {
       $4=a[$1,$2]
       if(FNR==1)
         line[$1,$2]="NR"
       if($4!="")
         print line[$1,$2],$1,$2,$3
     }' input.txt <(zcat clients.gz)

输出:

NR 姓名 ID 注释
1 迈克 2000 英尺
3 迈克 20002 酒吧

一行:

awk 'BEGIN{FS=OFS="\t"} NR==FNR{a[$1,$2]=$1 FS $2; line[$1,$2]=NR-1; next} {$4=a[$1,$2]; if(FNR==1) line[$1,$2]="NR"; if($4!="")print line[$1,$2],$1,$2,$3}' input.txt <(zcat clients.gz)

请参阅:基于两个关键列 awk8 个强大的 Awk 内置变量 - FS、OFS、RS、ORS、NR、NF、FILENAME、FNR连接两个文件

于 2020-01-26T09:05:18.943 回答
1
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ key = $1 FS $2 }
NR == FNR { map[key] = (NR>1 ? NR-1 : "NR"); next }
key in map { print map[key], $0 }

$ zcat clients.gz | awk -f tst.awk input.txt -
NR      name    ID      comment
1       Mike    2000    foo
3       Mike    20002   bar
于 2020-01-26T16:58:57.207 回答
1

[编辑]
我误解了前置行号的来源。已更正。

你会尝试以下方法:

declare -A num          # asscoiates each pattern to the line number
mapfile -t ary < <(tail -n +2 input.txt)
pat=$(IFS='|'; echo "${ary[*]}")
for ((i=0; i<${#ary[@]}; i++)); do num[${ary[i]}]=$((i+1)); done
printf "%s\t%s\t%s\t%s\n" "NR" "name" "ID" "comment"
zgrep -E -w "$pat" clients.gz | while IFS= read -r line; do
    printf "%d\t%s\n" "${num[$(cut -f 1-2 <<<"$line")]}" "$line"
done

输出:

NR  name    ID  comment
1   Mike    2000    foo
3   Mike    20002   bar
  • 第二行和第三行生成Mike 2000|Mike 20003|Mike 20002从 开始的搜索模式input.txt
  • 该线for ((i=0; i<${#ary[@]}; i++)); do ..创建了从模式到数字的映射。
  • 该表达式"${num[$(cut -f 1-2 <<<"$line")]}"从输出的第一个和第二个字段中检索行号。

如果性能仍然不令人满意,请考虑ripgrep哪个比grep或快得多zgrep

于 2020-01-26T09:11:42.443 回答