我有两个文件,如果文件1中的单词在文件2中不存在,我想在新文件(例如文件3)的相应行中生成单词false。否则,我想在相应行中输出true。
文件1:
a
b
c
d
文件2:
a
d
c
e
t
y
文件3:
true
false
true
true
有没有办法使用 awk/sed/grep 命令来做到这一点?
答案1
假设 file2 不为空,并且也没有太大到无法放入内存而不引起问题:
awk 'NR==FNR{a[$0]; next} {print ($0 in a ? "true" : "false")}' file2 file1
答案2
阅读man grep bash
,并执行类似 UNTESTED 的操作:
for pat in $(cat "file 1") ; do
ans="False"
grep --quiet "^$pat\$" "file 2" || \
ans="True"
echo -e "$pat\t$ans" >>"file 3"
答案3
$ perl -le '
# construct a partial regex from the first filename argument
my $re = join("|", split /\n+/, do { local(@ARGV,$/) = shift; <> });
# complete and pre-compile the regex
$re = qr/\b(?:$re)\b/;
# read and process stdin and/or remaining filename args
while(<>) {
print /$re/ ? "true" : "false"
}' file2 file1
true
false
true
true
此 perl 脚本读取第一个参数 ( ) 指示的整个文件file2
,并构造一个与文件每一行上的各个单词相匹配的正则表达式。正则表达式中的每个单词都由交替字符分隔|
。它假定文件每行包含一个单词,并且各行由一个或多个换行符分隔(这具有忽略空行的有用副作用)。
注意: 的每个单词都file2
将被解释为正则表达式。如果您希望将它们解释为固定字符串,请将行更改my $re ...
为:
my $re = join("|", map { quotemeta $_ } split /\n+/, do { local(@ARGV,$/) = shift; <> });
quotemeta 函数“引用”字符串中的所有正则表达式元字符,以便它们失去其特殊含义并被视为文字字符。看perldoc -f quotemeta
。该map
函数使{ quotemeta $_ }
块应用于返回的列表的每个元素split
。参见perldoc -f map
和perldoc -f split
。
顺便说一句,do { local(@ARGV,$/) = shift; <> })
这是一个相当常见的 Perl 习惯用法,用于“slurping”文件,即一次读入整个文件。还有许多其他方法可以做同样的事情,包括像文件::吸食者,但这很简单且可移植,并且不需要使用或安装任何库模块。
然后,该脚本使用qr
引用运算符来预编译正则表达式以提高性能(在每次循环中重新编译相同的正则表达式将极大地浪费 CPU 时间)。单词边界标记 ,\b
用于防止部分匹配,并?:
用于防止捕获匹配(这只会浪费时间,因为我们只需要检测匹配发生,不需要将匹配用于任何事情)。参见perldoc -f qr
和man perlre
正则表达式区分大小写,但可以使用正则i
表达式修饰符使其不区分大小写:
$re = qr/\b(?:$re)\b/i;
然后,该脚本读取任何剩余的输入,并且对于每一行输入,如果该行与正则表达式匹配,则打印“true”,否则打印“false”。因为它使用while(<>)
它将从标准输入和/或任何文件名参数读取数据。在此示例中,它从 读取输入file1
。
内存使用量与第一个文件的大小成正比 - 中的单词越多file2
,它使用的 RAM 就越多。当然,运行时间与第一个文件和所有其他输入的大小成正比。
答案4
tmp=$(mktemp)
comm -2 <(sort file1) <(sort file2) \
| sed -e 's/^\t.*/true/;t
c false' > "$tmp"
paste <(cat -n < "$tmp") \
<(cat -n file1 | sort -bk2) \
| sort -bk3,3n | cut -f2
输出:-
true
false
true
true
笔记:
- 第一步,我们对这两个文件进行排序,并通过 comm 运行它们,并抑制第二个文件。
- 接下来 sed 将识别 true/false 元素
- 最后,为了恢复原始顺序,我们对输出和编号排序的输入进行粘贴。