仅从文件中读取模式的一部分



我在一个文件中有一个字符串列表。我想找出添加到特定前缀时哪些字符串在另一个文件中不存在。

所以如果字符串列表是这样的

foo
bar
baz
qux

目标文件是这个

prefix-foo
prefix-barnotreally
prefix-baz

命令的输出应为

bar
qux

我知道-fgrep 标志,但据我所知,它不允许用户仅将文件中的字符串用作模式的一部分

> 另一种选择是使用标准的Unix工具join

join -t- -1 1 -2 2 -v 1 <(sort file1) <(sort -t- -k 2 file2)

该命令在某个联接字段上联接两个表。 它要求两个文件按连接字段排序,这就是我们需要两个排序命令的原因。 我们还可以通过使用临时文件使其更具可读性:

sort file1 > file1.sorted
sort -t- -k 2 file2 > file2.sorted
join -t- -1 1 -2 2 -v 1 file1.sorted file2.sorted

第一个sort命令只是对文件的行进行排序。 第二个排序命令按第二个字段(-k 2(排序,使用破折号作为字段分隔符(-t-(。

join命令还指定-作为字段分隔符 (-t-(,并选择第一个文件中的第一列作为连接键 (-1 1(,选择第二个文件中的第二列 (-2 2(。 输出仅限于第一个文件 (-v 1( 中不可配对的行。

如果您的文件非常大,则此解决方案比其他任何解决方案都更有效,但在大多数实际情况下,性能差异并不重要。

您可以使用进程替换从第二个文件中提取要传递给grep-f选项的字符串部分:

grep -vxFf <(cut -f2- -d- file2) file1
  • -v- 反转搜索;查找不匹配的行
  • -x- 匹配整条线
  • -F- 查找字符串,而不是正则表达式
  • <(cut -f2- -d- file2)- 从目标文件中提取字符串,留下前缀

您可以使用 bash 脚本,该脚本接收包含该格式字符串的文件作为第一个参数,并将该格式的文本文件作为第二个参数接收

#! /bin/bash
if [ $# -ne 2 ]; then
echo "Usage: $0 <file1> <file2>"
exit 1
fi
fStrings=$1
file=$2
while read string; do
cat $file | grep -qw $string
if [ $? -ne 0 ]; then
echo $string
fi
done < $fStrings

如果您熟悉awk,则可以使用它。下面是一个示例:

$ cat test.data
prefix-foo
prefix-barnotreally
prefix-baz
$ cat test.awk
BEGIN {
split("foo bar baz qux", a);
}
/^prefix-*/ {
gsub("^prefix-", "");
for (i in a)
if ($0 == a[i])
found[$0] = ""
}
END {
for (i in a)
if (!(a[i] in found))
print a[i]
}
$ awk -f test.awk test.data
bar
qux

with awk

awk 'NR==FNR{a=a " " $0;next} ! match(a,"\<"$0"\>")' targetfile liststrings

获取字符串 a 中的所有目标文件,而不打印在字符串 a 中找到的列表字符串行

最新更新