两个文件之间的Grep'\<'和'\>'

时间:2014-03-15 10:49:32

标签: bash grep

a.txt包含单词,b.txt包含字符串。

我想知道b.txt中有多少字符串以a.txt中的单词开头或结尾。

我在GREP用户手册中找到了这个: "假设我想搜索整个单词,而不是单词的一部分?           grep -w'你好' * 仅搜索整个单词的'hello'实例;它与'奥赛罗'不符。要获得更多控制权,请使用'\ _<'和'>'来匹配单词的开头和结尾。例如:

      grep 'hello\>' *

仅搜索以'hello'结尾的单词,因此它匹配单词'Othello'。"

但我不知道如何修改它来解决我的问题。

示例:a.txt

apple
peach
potato
green
big
pink

b.txt

greenapple
bigapple
rottenapple
pinkpeach
xxlpotatoxxx

输出

ends.txt

3 apple greenapple bigapple rottenapple
1 peach pinkpeach

starts.txt

1 green greenapple
1 big bigapple
1 pink pinkpeach

我在这里收到了一些想法: grep two files (a.txt, b.txt) - how many lines in b.txt starts (or ends) with the words from a.txt - output: 2 files with the results

但是由于a.txt包含大约50K行,而b.txt包含超过100M行,我认为,grep是唯一的解决方案。

4 个答案:

答案 0 :(得分:4)

最好的办法是编写一个脚本,该脚本将循环遍历包含模式的文件的每一行,并为另一个文件中的模式编译grep

以下内容将获取 startsWith 字符串:

while read -r w; do
  start=($(grep "^${w}" b.txt));
  (( ${#start[@]} != 0 )) && echo "${#start[@]} $w ${start[@]}";
done < a.txt

对你的样本输入执行它,它会产生:

1 green greenapple
1 big bigapple
1 pink pinkpeach

同样,你可以编写另一个单行程来获得 endsWith 字符串:

while read -r w; do
  end=($(grep "${w}$" b.txt));
  (( ${#end[@]} != 0 )) && echo "${#end[@]} $w ${end[@]}";
done < a.txt

会产生:

3 apple greenapple bigapple rottenapple
1 peach pinkpeach

编辑:如果要将输出重定向到单独的文件,可以在一个循环中执行这两个部分:

> startswith.txt     # Truncate the output files to begin with
> endswith.txt
while read -r w; do
  start=($(grep "^${w}" b.txt));
  (( ${#start[@]} != 0 )) && echo "${#start[@]} $w ${start[@]}" >> startswith.txt;
  end=($(grep "${w}$" b.txt));
  (( ${#end[@]} != 0 )) && echo "${#end[@]} $w ${end[@]}" >> endswith.txt;
done < a.txt

答案 1 :(得分:3)

在这里,awk将是我的第一选择。即使你有条件,它也应该表现得很好。

awk '
    NR == FNR {word[$1]; next} 
    {
        for (w in word) {
            if ($1 ~ "^" w) starts[w] = starts[w] $1 " "
            if ($1 ~ w "$") ends[w] = ends[w] $1 " "
        }
    } 
    END {
        for (w in ends) {
            n = split(ends[w], a)
            print n, w, ends[w] > "ends.txt"
        }
        for (w in starts) {
            n = split(starts[w], a)
            print n, w, starts[w] > "starts.txt"
        }
    }
' a.txt b.txt
$ cat ends.txt
3 apple greenapple bigapple rottenapple
1 peach pinkpeach
$ cat starts.txt
1 pink pinkpeach
1 big bigapple
1 green greenapple

答案 2 :(得分:1)

您可以使用简单的bash脚本:

#!/bin/bash

INPUT=a.txt
SEARCH=b.txt
OUTS=starts.txt
OUTE=ends.txt

while read line ; do
    echo -n "$line " >> "$OUTS"
    echo -n "$line " >> "$OUTE"
    grep "$line\>" "$SEARCH" | xargs >> "$OUTE"
    grep "\<$line" "$SEARCH" | xargs >> "$OUTS"
done < "$INPUT"

(这不会打印行前面的匹配数量)

答案 3 :(得分:1)

这个单行

for a in `cat a.txt` ; do echo $a ; grep -c $a\\\>\\\|\\\<$a b.txt ; done

生成此输出:

apple
3
peach
1
potato
0
green
1
big
1
pink
1

虽然它不是替代品产生的漂亮输出,但它是简洁的,只在a.txt

每行执行一次grep