Eh bien, je ne connais pas grand chose à la programmation chez bash, je suis nouveau dans ce domaine donc j'ai du mal à trouver un code pour itérer toutes les lignes d'un fichier txt, et compter combien de mots sont différents.
Exemple: si un fichier txt contient "Nory était catholique parce que sa mère était catholique"
Le résultat doit donc être 7
5 Réponses :
Bien sûr. Je suppose que vous êtes d'accord pour définir les «mots» comme des choses séparées par un espace? Dans ce cas, essayez quelque chose comme ceci:
tr -s " " "\n" < filename | sort -u | wc -l
Cette commande dit:
Vider le contenu du nom de fichier
Remplacez plusieurs espaces par un seul espace
Remplacez les espaces par une nouvelle ligne
Trier et "unifier" la liste
Imprimer le nombre de lignes
Selon le commentaire, vous pouvez techniquement vous en sortir sans utiliser cat si vous le souhaitez, avec ce qui suit:
sed -r -e "s/[ ]+/ /g" -e "s/ /\n/g" filename | sort -u | wc -l
De plus, à partir d'un autre commentaire, vous pouvez éventuellement utiliser tr
(surtout avec son indicateur -s pour gérer les espaces répétés) au lieu de sed
avec quelque chose comme:
cat filename | sed -r -e "s/[ ]+/ /g" -e "s/ /\n/g" | sort -u | wc -l
La morale de l'histoire est qu'il y a plusieurs façons d'accomplir ce genre de chose, sans parler des autres réponses complètes qui sont données ici :-) Ma réponse préférée à ce stade est celle d'Ed Morton que j'ai votée pour en conséquence.
Félicitations, vous remportez le prix "Utilisation inutile de chat" d'aujourd'hui :-) Essayez sed -r -e "s / [] + / / g" -e "s / / \ n / g" nom de fichier | trier ...
à la place.
Ha. Assez juste: p
S'ok, ça marche même avec ce truc mérite donc un vote positif.
sed -r -e "s / [] + / / g" -e "s / / \ n / g"
est identique à tr -s '' '\ n' < / code>
J'ai supprimé le wc -l pour voir comment cela fonctionne et j'ai découvert que cela fonctionne mais certains mots égaux n'ont pas été supprimés car ils sont séparés par des tabulations, c'était comme ceci Ex: mot mot mot
correct. Si vous utilisez la solution d'Ed Morton, elle gérera tous les séparateurs d'espaces blancs. Celui-ci gère simplement "" la séparation.
cat yourfile.txt | xargs -n1 | sort | uniq -c > youroutputfile.txt xargs -n1 = put one word per linesort = sortsuniq -c = counts occurrences of distinct valuessource
Utiliser xargs
fonctionnerait bizarrement. Par exemple, quote: "this is a quote"
compterait 2 mots. xargs
analyse les citations.
oh bizarre, pourquoi ne compterait-il que deux?
Vous manquez un cat
au début de cette commande? De plus, cela ne donne-t-il pas à chaque mot sa quantité individuelle plutôt que la quantité totale?
deuxième m'a deviné après avoir vu l'autre réponse et l'ai enlevée
xargs
(par défaut) prend en charge les guillemets, il analyse l'entrée entre guillemets comme un argument. Donc echo '123 "c'est entre guillemets"' | xargs -n1
affichera deux lignes.
@TravisG: Un autre problème avec xargs
, en plus des guillemets, est que la ponctuation fait partie des mots. Si l'entrée contient quelque chose comme A + B, C
(sans espaces), il s'agit d'un seul mot d'entrée pour xargs, pas trois. Une solution consisterait à diriger l’entrée d’abord via tr
et à remplacer tout ce qui n’est pas une lettre par un espace, et puis l’alimenter à xargs code>.
Je le ferais comme ça, avec des commentaires:
echo "Nory was a Catholic because her mother was a Catholic" | # tr replace # -s - squeeze # -c - complementary # [a-zA-Z0-9_] - all letters, number and underscore # but complementary set, so all non letters, not numbers and not underscores. # replace them by newline tr -sc '[a-zA-Z0-9_]' '\n' | # and sort unique and display count sort -u | wc -l
Testé sur repl bash .
A décidé d'utiliser [a-zA-Z0-9_]
, car c'est ainsi que GNU sed \ w extension correspond à un mot.
Pourquoi avez-vous besoin de sed là-bas? tr peut presser des séries de non-lettres avant de les remplacer
Pour supprimer les lignes vides. Ex. Bonjour, je m'appelle kamil.
entraînera une ligne vide de ,
remplacée par deux \ n \ n
.
echo Bonjour, je m'appelle kamil. | tr -cs [: alpha:] '\ n'
ne génère pas de lignes vides.
$ grep -o '[^[:space:]]*' file | sort -u | wc -l 7
Salut @Ed Morton, j'aime la réponse (je l'ai votée pour) mais je pense que ce serait mieux avec un +
de dire "un ou plusieurs non espaces" plutôt que le * code> qui dit "zéro ou plus" ... Il est possible que votre réponse gère cela en raison de l'indicateur -o (je ne suis pas sur un shell à tester) mais je pense que ce serait plus sémantiquement correct si rien d'autre si édité.
Si j'ai utilisé +
au lieu de *
, alors je devrais ajouter -E
pour prendre en charge les ERE ou apporter d'autres modifications, je pense que *
est très bien.
Ok alors, assez bien
Vous pouvez également mettre le texte en minuscules afin que les mots se comparent indépendamment de la casse.
Filtrez également les mots avec la classe de caractères [: alnum:]
, plutôt que [a-zA-Z0 -9_]
qui n'est valide que pour US-ASCII, et échouera dramatiquement avec le grec ou le turc.
#!/usr/bin/env bash echo "The uniq words are the words that appears at least once, regardless of casing." | # Turn text to lowercase tr '[:upper:]' '[:lower:]' | # Split alphanumeric with newlines tr -sc '[:alnum:]' '\n' | # Sort uniq words sort -u | # Count lines of unique words wc -l