如何使用grep统计目录中所有文件中所有单词的出现次数?但每个文件每个单词的计数仅增加一次

如何使用grep统计目录中所有文件中所有单词的出现次数?但每个文件每个单词的计数仅增加一次

我已经问过类似的问题,但人们误解了我的问题。我问如何生成每个单词的列表,每个文件每个单词的单词计数仅增加一次。

例如,我有一个包含 10 个文件的目录,我想使用 bash 命令生成一个单词列表,该列表的值介于 1-10 之间,具体取决于它们出现在文件中的数量:

10 The
10 and
8 bash
7 command
6 help....

ETC。

我已经知道它将grep -l word *| wc -l搜索单个单词,但我想创建所有单词的列表。

有没有办法将tr '[A-Z]' '[a-z]' | tr -d '[:punct:]'其与大写字母的单词不重复并删除标点符号结合起来?

答案1

我会在这里使用 perl :

perl -T -lne '
  for (/\w+/g) {$count{lc $_}->{$ARGV}=undef}
  END {print "$_: " . keys %{$count{$_}} for keys %count}' ./*

它构造了一个哈希值,哈希值$count{word}是对哈希值的引用,其键是在其中找到的文件的名称word(以及我们不关心的值,此处设置为undef)。

最后,我们只计算每个哈希值(即每个找到的单词)的元素数量(即文件数量)。

答案2

我刚看到原版在这里回答作者:@Mehmet 在搜索不相关的内容时,我发现虽然它有效,但效率非常低,需要再次读取每个文件以获取所有文件中的每个唯一单词! @Jeff 的第二个答案相当复杂,尽管有解释,最糟糕的是它遭受了罪恶cat file |

只需要对所有数据进行一次传递即可,并且可以通过有效组合早期答案来制定:

find . -maxdepth 1 -type f -print |
while read file; do
    egrep -h -o "[[:alnum:]][[:alnum:]_-]*" "$file" |
    tr '[A-Z]' '[a-z]' |
    sed "s|^|$file\||"
done |
sort -t '|' -k 2 |
uniq |
awk -F '|' '{
    if (lw != $2) {
        print fc " " lw;
        fc = 0;
    }
    lw = $2;
    fc++;
}'

请注意,如果您的文件名包含路径和/或包含空格,则字段分隔符的选择很重要。我选择这个|字符是因为它永远不应该是打印的单词的一部分,egrep并且它不可能出现在文件或目录名称中。

答案3

这应该从所有文件中获取所有单词,对它们进行排序并获取唯一的单词,然后迭代这些单词并计算它出现在多少个文件中。

# find all words from all files within the directory
grep -o -h -E '\w+' directory/*|sort -u | \
while read word;
do
        # iterate through each word and find how many files it occurs
        c=`grep -l "$word" directory/*|wc -l`
        echo "$c $word";
done

答案4

这是单独处理目录中每个文件的方法:

for f in yourdirectory/*; do cat "$f" |

这就是我从文本数据中过滤掉除单词之外的所有内容的方法:

sed 's/\.$//;s/\.\([^0-9]\)/\1/g;s/[][(),;:?!]//g' | tr [A-Z] [a-z] |

但你的方法可能同样有效。 (我想确保不要删除连字符单词中的连字符,也不要删除缩写词中的撇号。)

无论哪种方式,请继续执行以下操作:

tr -s ' ' '\012' | sort -u ; done |

这会生成一个每个文件一个单词列表,所以现在只需:

sort | uniq -c

如果您想要从最频繁到最不频繁的列表,只需添加|sort -nr

您可能还需要添加一些额外的标点符号,例如{}上面末尾的列表sed,具体取决于您的输入数据。

相关内容