Supposons que j'ai deux files a.txt
et b.txt
. Je veux find tous les mots dans a.txt
qui apparaissent dans b.txt
.
Existe-t-il une command spécifique pour le faire?
Avec bash
, zsh
et certaines implémentations de ksh
:
comm -12 <(tr -s '[:space:]' '[\n*]' < a.txt | sort -u) \ <(tr -s '[:space:]' '[\n*]' < b.txt | sort -u)
Là, le mot est une séquence de caractère sans espacement (attention à GNU tr
, cela ne fonctionne pas avec des caractères d'espacement multi-octets).
comm
trouve les lignes communes entre deux files sortingés. Sans options, il imprime 3 colonnes: les lignes uniquement dans le file1, les lignes uniquement dans le file2 et les lignes communes aux deux. Vous ajoutez -1
, -2
, -3
pour supprimer les colonnes correspondantes de la sortie. Donc comm -12
ne quitte que la troisième colonne (les lignes communes).
tr -s '[:space:]' '[\n*]'
permet de classr chaque caractère de l' space
de class en newlines, pour mettre chaque mot sur sa propre ligne.
sort -u
sortinge et supprime les duplicates de la sortie de tr
.
La substitution de process <(...)
canalise les sorties des commands tr|sort
à comm
.
Avec zsh
:
w1=($(<a.txt)) w2=($(<b.txt)) print -rl -- ${(u)${w1:*w2}}
Là, le mot est une séquence de caractères autres que l'espace, l'onglet, le nul et le saut de ligne (avec la valeur par défaut de $IFS
).
$(<a.txt)
est une version optimisée de $(cat a.txt)
où zsh
lit le contenu du file sans invoquer cat
, puisqu'il n'est pas cité, il subit un fractionnement de mots (mais pas de globes contrairement aux autres shells ).
Donc w1
et w2
sont des arrays contenant tous les mots dans a.txt
et b.txt
.
${w1:*w2}
est un opérateur zsh qui donne l'intersection de deux arrays (les éléments communs aux deux). (u)
est un indicateur d'expansion de paramètre qui conserve des éléments uniques (supprime les duplicates).
print -rl
imprime chaque argument un par ligne.
# Create dummy text file containing two words $ echo -e "overflow\ngrep" > b # Search in file for lines containing one word from file b $ grep --color --fixed-ssortingngs --file b /usr/share/dict/words
Résultat sur mon système:
overflow overflow's overflowed overflowing overflows
Ajoutez le paramètre –only-matching (-o) pour get uniquement les mots et non la ligne entière dans laquelle ils apparaissent.
En supposant que les mots dans les files sont séparés par LF et que les mots ne contiennent que des caractères "gentils" et qu'il n'y a pas de LF dans le file b.txt,
egrep `tr '\n' '|' < b.txt` a.txt
pourrait faire l'affaire.
Bien que vous ne travailliez pas au niveau des mots, il vous serait plus utile de travailler sur les lignes pour vous ou quelqu'un d'autre à la search d'une réponse.
diff --left-column --from-file=a.txt --to-file=b.txt
Compare le file a.txt au file b.txt ne produisant que des lignes communes.