通讯

通讯

我试图做简单的事情grep,所以我将从中获取存在于且不存在的grep -v行。a.txtb.txtc.txt

3 个文件的示例

a.txt:

a
b
c
d
e

up.txt:

a.up
b.up
c.up

dw.txt:

a.dw
b.dw

期望的输出:

c

我编写了下面的代码,但 每次grep看起来都是一行,而不是一个整体:$(sed...)

sed 's/.up//' /tmp/b.txt | grep -f /tmp/a.txt | grep -vf $(sed 's/.dw//' /tmp/c.txt)

答案1

使用单一快速 GNUawk命令:

awk -F'.' \
'{
     if (ARGIND == 1) a[$1];
     else if (ARGIND == 2 && $1 in a) comm[$1];
     else if (ARGIND == 3){
         delete a;
         if ($1 in comm) delete comm[$1]
     }
 }
 END{ for (i in comm) print i }' a.txt b.txt c.txt

输出:

c

  • -F'.'-.视为字段分隔符
  • ARGINDARGV-当前正在处理的文件(命令行参数数组)中的索引
  • comm- 数组常见的a.txt前 2 个文件 (和b.txt)之间的项目

答案2

假设文件都已排序,并且我们使用的是能够理解进程替换的 shell(例如bash):

$ join -t . -v 1 -o 0 <( join -t . a.txt b.txt ) c.txt
c

或者,对于其他外壳,

$ join -t . a.txt b.txt | join -t . -v 1 -o 0 - c.txt
c

这使用join两次来执行文件之间的关系连接。数据被解释为点分隔字段(带有-t .)。

a.txt和之间的连接b.txt是直接的并且产生

a.up
b.up
c.up

这些是两个文件中第一个点分隔字段都出现在两个文件中的所有行。输出由连接字段(abc)组成,后跟两个文件中的其他字段(仅b.txt包含任何进一步的数据)。

第二个连接有点特殊。我们-v 1要求查看第一个文件中的条目(上面的中间结果),这些条目不能与第二个文件中的任何行配对c.txt。此外,我们只要求查看连接字段本身 ( -o 0)。如果没有-o标志,我们就会得到c.up结果。


如果文件未排序,则每次出现的文件名都可以在命令中file替换为。<( sort file )

答案3

通讯

假设文件已排序,并删除了重复行:

comm -12 a.txt <(cut -d. -f1 b.txt) | comm -23 - <(cut -d. -f1 c.txt)

这是为 Ubuntu 编写的,使用 Bash 和 GNU 实用程序,但希望它也适用于其他操作系统。

解释

  • comm -12打印两个文件共享的行(man comm详细信息请阅读)
  • <(...)进程替换 - 使用命令代替输入文件
  • cut -d. -f1对于每一行,删除第一个点之后的所有内容
  • comm -23打印第一个文件特有的行
  • -从标准输入而不是文件读取

答案4

perl -F\\. -lane '
   $h{@ARGV}{$F[0]}++,next if @ARGV;
   print if exists $h{2}{$_} && !exists $h{1}{$_};
' up.txt dw.txt a.txt

使用顶级键“2”和“1”构建哈希 %h,其中 2 引用第一个参数 (up.txt),1 引用 dw.txt。对于给定的数据,哈希结构将类似于:(顺序可能不同)

%h = (
   1 => { a => 1, b => 1, },
   2 => { a => 1, b => 1, c => 1, },
);

可以看出,主哈希 %h 中有两个迷你哈希。因此,当需要读取第三个参数 (a.txt) 时,我们根据该记录是否可以在迷你哈希 %2 中看到(作为键)并且在迷你哈希 %1,位于主哈希 %h 内(也称为哈希的哈希或 HoH)。

相关内容