Zápočtová úloha 42, F2470

Zadání: Ze dvou adresářů (včetně jejich podadresářů) vypiš soubory, které se stejně jmenují, ale liší obsahem. Vypiš vždy novější soubor s celou cestou a jeho čas modifikace.

Úlohu řeším nejspíše dosti neefektivním způsobem. V první části skriptu vyhledám soubory v testovacích složkách, vypočítám k nim kontrolní součty a vyberu ty soubory, které mají stejné jméno, ale liší se obsahem. V druhé části už jen formátuji, přidám čas poslední modifikace a vyberu nejnovější. Tento postup nemá rád soubory s bílými znaky, což ovšem lze vyřešit separátně pomocí přejmenování souborů, resp. adresářů.

$ find -name "* *" -type f | rename 's/ /_/g' #přejmenuje soubory, místo mezer dá podtržítka
$ find -name "* *" -type d | rename 's/ /_/g' #přejmenuje adresáře, místo mezer dá podtržítka

Začnu vyhledáním pomocí find ve dvou testovacích složkách ~/test1/ a ~/test1/, zajímají mě pouze soubory -type f. Ty pošlu rourou přes xargs do md5sum, který vypočítá k souborům jejich kontrolní součty.

$ find ~/test1/ ~/test2/ -type f | xargs md5sum

Teď následuje procedura, která kontroluje výskyt jmen (předpokládám, že jména neobsahují /, pokud ano, lze to vyřešit podobně jako s mezerami). V awk nastavím oddělovač / pomocí -F/, díky čemuž je jméno souboru vždy na pozici $NF. Dále kontroluji, jestli ve vektoru jmena[] na pozici, kterou zrovna čtu už něco je. Pokud ano, zkontroluji jestli se liší od ostatních a případně zvýším počet výskytů. Pak do vektoru připíši čtený řádek a zapamatuji si kontrolní sumu, pro případ porovnání. Když awk skončí se čtením řádků, vypíše sumy a cesty ke vybraným souborům.


$ find ~/test1/ ~/test2/ -type f | xargs md5sum | 
  awk -F/ '{if(jmena[$NF]) {if(md5[$NF]!=$1) {vyskyty[$NF]++}}
    jmena[$NF]=jmena[$NF] $0"\n"  
    md5[$NF]=$1 }
    END { for( d in vyskyty ) {printf jmena[d]}}'

Nyní už je postup docela přímočarý, pomocí cut -c oříznu sumy na začátku řádku, jména souborů pošlu rourou do podrobného ls -l, kde si navolím long-iso formát času. Opět pomocí cut -c oříznu nezajímavé položky a už jednou použitým trikem s awk -F/ vyrobím jména souborů kvůli třídění. Soubory roztřídím pomocí sort -k4 -k1r -k2r, kde první volba znamená primární třídění podle jména souboru a další dvě jsou podle datumu a času obráceně, tak aby nové soubory byly navrchu. Na závěr pomocí uniq -f 3 vyberu první řádky s unikátním jménem ve třetím sloupci. Celý skript níže:


$ find ~/test1/ ~/test2/ -type f | xargs md5sum |
  awk -F/ '{if(jmena[$NF]) {if(md5[$NF]!=$1) {vyskyty[$NF]++}}
    jmena[$NF]=jmena[$NF] $0"\n"  
    md5[$NF]=$1 }   
    END { for( d in vyskyty ) {printf jmena[d]}}' | 
  cut -c35- | xargs ls -l --time-style=long-iso | cut -c28- | awk -F/ '{print($0" "$NF)}' | sort  -k4 -k1r -k2r | uniq -f 3