Ok, j'ai deux listes liées 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. Je dois ensuite passer en boucle sur ces lignes et y effectuer des actions selon qu’elles ont été ajoutées ou supprimées.
Comment puis-je faire cela à bash?
Utilisez la commande comm(1)
pour comparer les deux fichiers. Ils doivent tous les deux être triés, ce que vous pouvez faire au préalable s'ils sont volumineux, ou vous pouvez le faire en ligne avec bash process substitution .
comm
peut combiner les indicateurs -1
, -2
et -3
en indiquant le fichier à supprimer (unique pour le fichier 1, unique pour le fichier 2 ou commune aux deux).
Pour obtenir les lignes uniquement dans l'ancien fichier:
comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)
Pour obtenir les lignes uniquement dans le nouveau fichier:
comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)
Vous pouvez insérer cela dans une boucle while read
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.
La commande diff fera la comparaison pour vous.
par exemple.,
$ diff /tmp/oldList /tmp/newList
Voir le lien de la page de manuel ci-dessus pour plus d'informations. Cela devrait prendre en charge votre première partie de votre problème.
Pensez à utiliser Ruby si vos scripts ont besoin de lisibilité.
Pour obtenir les lignes uniquement dans l'ancien fichier:
Ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
Pour obtenir les lignes uniquement dans le nouveau fichier:
Ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"
Vous pouvez alimenter cela dans une boucle de lecture while 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 vieux, mais pour être complet, nous devrions dire que si vous avez un très grand ensemble, la solution la plus rapide serait d’utiliser diff pour générer un script, puis l’alimenter 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 --changed-group-format. Consultez la page de manuel diff.
Avez-vous essayé diff
$ diff /tmp/oldList /tmp/newList
$ man diff
J'utilise typiquement:
diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"
L'option grep -v
inverse la correspondance:
-v, --invert-match Les lignes sélectionnées sont celles qui ne correspondent à aucun des pat -.__ spécifiés. sternes.
Donc, dans ce cas, il prend les résultats diff
et omet ceux qui sont courants.