我试图做简单的事情grep
,所以我将从中获取存在于且不存在的grep -v
行。a.txt
b.txt
c.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'.'
-.
视为字段分隔符ARGIND
ARGV
-当前正在处理的文件(命令行参数数组)中的索引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
这些是两个文件中第一个点分隔字段都出现在两个文件中的所有行。输出由连接字段(a
、b
、c
)组成,后跟两个文件中的其他字段(仅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)。