我在我的 unix shell 中使用了很多 grep awk sort 来处理中等大小(大约 10M-100M 行)制表符分隔的列文本文件。在这方面,unix shell 是我的电子表格。
但是我有一个大问题,那就是在给定 ID 列表的情况下选择记录。
有table.csv
与格式文件id\tfoo\tbar...
和ids.csv
文件与IDS的名单,只能从选择的记录table.csv
和存在于ID ids.csv
。
一种/sf/ask/961260681/但使用 shell,而不是 perl。
grep -F
如果 id 宽度可变,显然会产生误报。
join
是我永远想不通的实用程序。首先,它需要按字母顺序排序(我的文件通常按数字排序),但即便如此,我也无法在不抱怨顺序不正确和跳过一些记录的情况下使其正常工作。所以我不喜欢它。^id\t
当 id 数量很大时,使用-s对文件执行 grep -f非常慢。
awk
很麻烦。
对此有什么好的解决方案吗?用于制表符分隔文件的任何特定工具?额外的功能也将是最受欢迎的。
UPD:更正sort
->join
ter*_*don 26
我猜你的意思grep -f
不是,grep -F
但你实际上需要两者的组合和-w
:
grep -Fwf ids.csv table.csv
Run Code Online (Sandbox Code Playgroud)
你得到误报的原因是(我猜,你没有解释)因为如果一个 id 可以包含在另一个中,那么两者都会被打印出来。-w
消除了这个问题并-F
确保您的模式被视为字符串,而不是正则表达式。来自man grep
:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by
newlines, any of which is to be matched. (-F is specified by
POSIX.)
-w, --word-regexp
Select only those lines containing matches that form whole
words. The test is that the matching substring must either be
at the beginning of the line, or preceded by a non-word
constituent character. Similarly, it must be either at the end
of the line or followed by a non-word constituent character.
Word-constituent characters are letters, digits, and the
underscore.
-f FILE, --file=FILE
Obtain patterns from FILE, one per line. The empty file
contains zero patterns, and therefore matches nothing. (-f is
specified by POSIX.)
Run Code Online (Sandbox Code Playgroud)
如果您的误报是因为 ID 可以出现在非 ID 字段中,请改为循环遍历您的文件:
while read pat; do grep -w "^$pat" table.csv; done < ids.csv
Run Code Online (Sandbox Code Playgroud)
或者,更快:
xargs -I {} grep "^{}" table.csv < ids.csv
Run Code Online (Sandbox Code Playgroud)
就个人而言,我会这样做perl
:
perl -lane 'BEGIN{open(A,"ids.csv"); while(<A>){chomp; $k{$_}++}}
print $_ if defined($k{$F[0]}); ' table.csv
Run Code Online (Sandbox Code Playgroud)
该join
实用程序是您想要的。它确实需要对输入文件进行词法排序。
假设您的 shell 是 bash 或 ksh:
join -t $'\t' <(sort ids.csv) <(sort table.csv)
Run Code Online (Sandbox Code Playgroud)
无需排序,通常的 awk 解决方案是
awk -F '\t' 'NR==FNR {id[$1]; next} $1 in id' ids.csv table.csv
Run Code Online (Sandbox Code Playgroud)