Comment countr les occurrences de tous les mots dans tous les files d'un directory en utilisant grep? Mais avec le count incrémenté seulement une fois par mot par file

J'ai déjà posé une question similaire mais les gens ont mal compris ce que je demandais. Je demandais comment générer une list de chaque mot avec un nombre de mots incrémenté seulement une fois par mot par file.

Par exemple, j'ai un directory avec 10 files, je veux générer une list de mots en utilisant les commands bash qui indique une valeur de 1-10 en fonction du nombre de files dans lesquels ils apparaissent:

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

etc.

Je sais déjà que grep -l word *| wc -l grep -l word *| wc -l cherchera un seul mot mais je veux créer une list de tous les mots.

Y at-il un moyen de combiner cela avec tr '[AZ]' '[az]' | tr -d '[:punct:]' tr '[AZ]' '[az]' | tr -d '[:punct:]' pour que les mots avec des majuscules ne soient pas dupliqués et que la ponctuation soit supprimée?

Je voudrais utiliser perl ici:

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

Cela construit un hachage de hachage $count{word} est une reference à un hachage dont les keys sont les noms des files dans lesquels ce word se trouve (et les valeurs qui ne nous intéressent pas, ici définies par undef ).

En fin de count, nous comptons simplement le nombre d'éléments (donc le nombre de files) pour chacun de ces hachages (donc pour chacun des mots trouvés).

Je viens de find la réponse originale de @Mehmet en cherchant quelque chose sans rapport et je vois que même si cela fonctionne, c'est horriblement inefficace, nécessitant que chaque file soit lu à nouveau pour chaque mot unique dans tous les files! La deuxième réponse de @Jeff est plutôt alambiquée malgré l'explication et la pire de toutes, elle souffre du cat file | péché!

Un seul passage sur toutes datatables est tout ce qui est nécessaire et il peut être formulé en combinant efficacement les réponses antérieures:

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

Notez que le choix du séparateur de champs est important si vos noms de files incluent des paths et / ou s'ils incluent des espaces. J'ai choisi le | caractère car il ne devrait jamais faire partie d'un mot imprimé par egrep et il est peu probable qu'il apparaisse jamais dans un file ou un nom de directory.

Cela devrait get tous les mots de tous les files, les sortinger et get des mots uniques, parcourir les mots et countr le nombre de files dans lesquels il se trouve.

 # 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 

Voici comment traiter chaque file dans un directory individuellement:

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

C'est ainsi que je filter tout sauf les mots des données textuelles:

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

Mais votre méthode peut fonctionner aussi bien. (Je voulais m'assurer de ne pas supprimer les traits d'union des mots traits d'union, ni les apostrophes des contractions).

De toute façon, continuez comme suit:

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

Cela fait une list de mots un par file, alors maintenant juste:

 sort | uniq -c 

Si vous voulez que la list soit la plus fréquente ou la less fréquente, |sort -nr simplement |sort -nr .

Vous devrez peut-être append des ponctuations supplémentaires, telles que {} à la list à la fin du sed ci-dessus, en fonction de vos données d'input.