Bash-différence entre deux listes
Ok, j'ai deux listes connexes sur ma boîte linux dans des fichiers texte:
/tmp/oldList
/tmp/newList
je dois comparer ces listes pour voir quelles lignes ont été ajoutées et quelles lignes ont été supprimées. J'ai ensuite besoin de boucler ces lignes et d'effectuer des actions sur celles-ci selon qu'elles ont été ajoutées ou supprimées. Comment je fais ça à bash?
5 réponses
comm(1)
commande pour comparer les deux fichiers. Ils ont tous les deux besoin d'être triés, ce que vous pouvez faire à l'avance s'ils sont grands, ou vous pouvez le faire en ligne avec bash substitution de procédé.
comm
peut prendre une combinaison des drapeaux -1
,-2
et -3
indiquant le fichier à supprimer (unique au fichier 1, unique au fichier 2 ou commun aux deux).
Pour obtenir les lignes que dans l'ancien fichier:
comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)
Pour obtenir de l' les lignes que dans le nouveau fichier:
comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)
Vous pouvez nourrir que dans un while read
boucle pour traiter chaque ligne:
while read old ; do
...do stuff with $old
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList))
et de même pour les nouvelles lignes.
commande diff fera la comparaison pour vous.
e.g.,
$ diff /tmp/oldList /tmp/newList
voir le lien de la page de manuel ci-dessus pour plus d'informations. Cela devrait prendre soin de votre première partie de votre problème.
envisagez D'utiliser Ruby si vos scripts ont besoin de lisibilité.
Pour obtenir les lignes que dans l'ancien fichier:
ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
Pour obtenir les lignes que dans le nouveau fichier:
ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"
vous pouvez l'insérer dans une boucle de lecture pour traiter chaque ligne:
while read old ; do
...do stuff with $old
done < ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
Ceci est ancien, mais pour être complet nous devrions dire que si vous avez un ensemble vraiment grand, la solution la plus rapide serait d'utiliser diff pour générer un script et ensuite le source, comme ceci:
#!/bin/bash
line_added() {
# code to be run for all lines added
# $* is the line
}
line_removed() {
# code to be run for all lines removed
# $* is the line
}
line_same() {
# code to be run for all lines at are the same
# $* is the line
}
cat /tmp/oldList | sort >/tmp/oldList.sorted
cat /tmp/newList | sort >/tmp/newList.sorted
diff >/tmp/diff_script.sh \
--new-line-format="line_added %L" \
--old-line-format="line_removed %L" \
--unchanged-line-format="line_same %L" \
/tmp/oldList.sorted /tmp/newList.sorted
source /tmp/diff_script.sh
Les lignes modifiées apparaîtront comme supprimées et ajoutées. Si vous n'aimez pas cela, vous pouvez utiliser l'option --changé-groupe-format. Consultez la page de manuel diff.
Avez-vous essayé diff
$ diff /tmp/oldList /tmp/newList
$ man diff