Tijd voor een fijne shell one-liner! Ik heb ergens een scripje lopen dat dagelijks een database backupje maakt. Als er die dag niks aan de database veranderd is, zal de inhoud van de backup hetzelfde zijn als de dag ervoor. Met de volgende regel code ruim je in 1 klap alle duplicaten op:
find . -type f -exec md5sum '{}' \; | sort | awk '{ print $2 " " $1 }' | uniq -d -f 1 | awk '{ print "rm " $1 }' | sh
Dan nu de verklaring van deze hocus pocus! Hier nog een keer regel voor regel:
find . -type f -exec md5sum '{}' \; |
sort |
awk '{ print $2 " " $1 }' |
uniq -d -f 1 |
awk '{ print "rm " $1 }' |
sh
Find zoekt vanuit de huidige directory naar bestanden en voert voor elk gevonden bestand het commando md5sum uit. Md5sum maakt een hash van de inhoud van het bestand.
De output van de find/md5sum regel ziet er zo uit:
d41d8cd98f00b204e9800998ecf8427e ./file1
370f8e6d24325596c6c4f87182a04c96 ./file2
d41d8cd98f00b204e9800998ecf8427e ./copy_of_file1
1a25ba6ec5426ac337f050287abdf8cb ./file3
Met het pipe symbool (|) wordt de output telkens doorgestuurd naar de volgende stap. Na sort zie je dat de identieke files al netjes onder elkaar komen te staan:
1a25ba6ec5426ac337f050287abdf8cb ./file3
370f8e6d24325596c6c4f87182a04c96 ./file2
d41d8cd98f00b204e9800998ecf8427e ./copy_of_file1
d41d8cd98f00b204e9800998ecf8427e ./file1
Met awk draaien we de volgorde van de kolommen om. Dit is nodig voor de volgende stap:
./file3 1a25ba6ec5426ac337f050287abdf8cb ./file2 370f8e6d24325596c6c4f87182a04c96 ./copy_of_file1 d41d8cd98f00b204e9800998ecf8427e ./file1 d41d8cd98f00b204e9800998ecf8427e
Nu kan uniq z’n werk doen. Zonder argument laat alle duplicaten uit een gesorteerde lijst weg. We zijn echter in de duplicaten geinteresseerd, en daar is de -d optie voor. Omdat de lijst per definitie geen duplicaten bevat, vertellen we met de optie -f 1 de eerste kolom te negeren. Er is geen optie om de laatste kolom te negeren, vandaar de vorige stap. De lijst ziet er nu als volgt uit:
./copy_of_file1 d41d8cd98f00b204e9800998ecf8427e
We hebben de boosdoener te pakken!!! Met de tweede awk regel maken we het commando om het bestand op te ruimen:
rm ./copy_of_file1
Dit resultaat hoeft alleen nog maar uitgevoerd te worden. Dat gaat heel makkelijk met een pipe naar de shell. Voor het testen is het wel zo handig om | sh nog even weg te laten. Je kunt dan rustig controleren of je tevreden bent met het resultaat.
Opmerking:
Deze code kan niet omgaan met spaties in bestandsnamen. Weer een goede rede om geen spaties te gebruiken
.