从文本文件中选择具有在另一个文件中列出的 id 的行

ala*_*mar 19 shell csv

我在我的 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)


gle*_*man 9

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)