使用 bash 查询大型制表符分隔文件
Using bash to query a large tab delimited file
我有一个姓名和 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
clients.gz 中的每个 "\t"
都是唯一标识符。 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[=14=]q
}' input.txt |
bash > subset.txt
使用 GNU awk 和 bash:
awk 'BEGIN{FS=OFS="\t"}
# process input.txt
NR==FNR{
a[,]= FS
line[,]=NR-1
next
}
# process <(zcat clients.gz)
{
=a[,]
if(FNR==1)
line[,]="NR"
if(!="")
print line[,],,,
}' input.txt <(zcat clients.gz)
输出:
NR name ID comment
1 Mike 2000 foo
3 Mike 20002 bar
作为一行:
awk 'BEGIN{FS=OFS="\t"} NR==FNR{a[,]= FS ; line[,]=NR-1; next} {=a[,]; if(FNR==1) line[,]="NR"; if(!="")print line[,],,,}' input.txt <(zcat clients.gz)
参见:Joining two files based on two key columns awk and 8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR
[编辑]
我误解了前置行号的来源。更正。
你会尝试以下方法吗:
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
- 第二行和第三行从
input.txt
. 生成搜索模式 Mike 2000|Mike 20003|Mike 20002
- 行
for ((i=0; i<${#ary[@]}; i++)); do ..
从
图案到数字。
- 表达式
"${num[$(cut -f 1-2 <<<"$line")]}"
检索行
来自输出的第一个和第二个字段的数字。
如果性能还不够理想,请考虑ripgrep
,比grep
或zgrep
快很多。
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ key = FS }
NR == FNR { map[key] = (NR>1 ? NR-1 : "NR"); next }
key in map { print map[key], [=10=] }
$ zcat clients.gz | awk -f tst.awk input.txt -
NR name ID comment
1 Mike 2000 foo
3 Mike 20002 bar
我有一个姓名和 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
clients.gz 中的每个 "\t"
都是唯一标识符。 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[=14=]q
}' input.txt |
bash > subset.txt
使用 GNU awk 和 bash:
awk 'BEGIN{FS=OFS="\t"}
# process input.txt
NR==FNR{
a[,]= FS
line[,]=NR-1
next
}
# process <(zcat clients.gz)
{
=a[,]
if(FNR==1)
line[,]="NR"
if(!="")
print line[,],,,
}' input.txt <(zcat clients.gz)
输出:
NR name ID comment 1 Mike 2000 foo 3 Mike 20002 bar
作为一行:
awk 'BEGIN{FS=OFS="\t"} NR==FNR{a[,]= FS ; line[,]=NR-1; next} {=a[,]; if(FNR==1) line[,]="NR"; if(!="")print line[,],,,}' input.txt <(zcat clients.gz)
参见:Joining two files based on two key columns awk and 8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR
[编辑]
我误解了前置行号的来源。更正。
你会尝试以下方法吗:
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
- 第二行和第三行从
input.txt
. 生成搜索模式 - 行
for ((i=0; i<${#ary[@]}; i++)); do ..
从 图案到数字。 - 表达式
"${num[$(cut -f 1-2 <<<"$line")]}"
检索行 来自输出的第一个和第二个字段的数字。
Mike 2000|Mike 20003|Mike 20002
如果性能还不够理想,请考虑ripgrep
,比grep
或zgrep
快很多。
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ key = FS }
NR == FNR { map[key] = (NR>1 ? NR-1 : "NR"); next }
key in map { print map[key], [=10=] }
$ zcat clients.gz | awk -f tst.awk input.txt -
NR name ID comment
1 Mike 2000 foo
3 Mike 20002 bar