Postupy na Linuxu - hashování
Pokud potřebujete na Debianu 10 ověřit změnu souboru (např. že během kopírování nebyl poškozen)…
Zadání
Pro svůj systém zálohování potřebuji skript, který ke každému souboru vyrobí unikátní otisk (hash).
Takže třeba pro ahoj.txt
vyrobí ahoj.hash
obsahující otisk souboru ahoj.txt
.
Hashovací funkce
Protože počítám se zálohováním hromady malých i dost velkých souborů, potřebuji opravdu rychlou funkci, která zvládne např. hash DVD v rozumném čase. Přesně takovou funkcí by měl být algoritmus xxhash.
Instalace na Debian 10
sudo apt update sudo apt-get install xxhash
Použití
xxh64sum <soubor>
vypíše hash spočítaný 64bitovým algoritmem a název souboru- pokud výsledek uložíme do souboru, pak jím lze kontrolovat změnu souboru
xxh64sum ahoj.txt > ahoj.check
xxh64sum -c ahoj.check
- tady se provede kontrola, zda soubor vahoj.check
existuje a je nezměněný. Výsledkem je název souboru a OK nebo FAILED
- v souboru předkládaném kontrole může být vícero hashů a xxh64sum je ověří všechny - viz následující příklad
Kontrola změny souborů v adresáři
ls -I *.hash | xargs xxh64sum > soubory.hash
- vyrobí seznam souborů v adresáři (mimo .hash) včetně jejich hashů
- soubory .hash ignoruji (
-I *.hash
) protože by se mi ohashoval i samotný výsledek (a to nechci)
xxh64sum -c soubory.hash | grep ': FAILED' | awk -F: '{print $1}' > zmenene.hash
- do souboru
zmenene.hash
vypíše seznam změněných souborů -F:
říká, že oddělovačem pro awk bude dvojtečka aprint $1
zase že chceme vypsat první sloupec
user@srv:~$ ls test2.txt test3.txt test.txt user@srv:~$ ls -I *.hash | xargs xxh64sum > soubory.hash user@srv:~$ cat soubory.hash 4eaa915d9d571b1e test2.txt 1f57dd2f7c75f00b test3.txt 6659c6ffae797c28 test.txt user@srv:~$ echo a jeste neco >> test3.txt user@srv:~$ cat test3.txt nejaky dalsi text bla bla bla bla bla a jeste neco user@srv:~$ xxh64sum -c soubory.hash test2.txt: OK test3.txt: FAILED test.txt: OK 1 computed checksums did NOT match user@srv:~$ xxh64sum -c soubory.hash | grep ': FAILED' | awk -F: '{print $1}' > zmenene.hash user@srv:~$ cat zmenene.hash test3.txt
Skript
Zpátky k zadání - zde je skript, který vezme parametry a pro každý z nich vyrobí soubor s příponou .hash obsahující jeho hash:
#!/bin/bash args=("$@") args_cnt=${#args[@]} for ((i=0;i<$args_cnt;i++)); do soubor=${args[${i}]} vynechat=".*\.(hash|archived)$" # pokud je na vstupu .hash nebo .archived soubor, pak jej vynechame if [[ ! $soubor =~ $vynechat ]]; then xxh64sum $soubor > $soubor.hash fi done
- na vstupu ignoruje soubory .hash a .archived
- pokud k souboru
ahoj.txt
již existuje souborahoj.txt.hash
, přepíše jej - použití:
user@srv:~$ ls mkhash.sh test2.txt test3.txt test.txt user@srv:~$ ls -I *.sh | xargs ./mkhash.sh user@srv:~$ ls mkhash.sh test2.txt.hash test2.txt test3.txt.hash test3.txt test.txt.hash test.txt user@srv:~$ xxh64sum -c test3.txt.hash test3.txt: OK user@srv:~$
- použití při zálohování celé struktury:
- skript i příkazy spouštím z kořene struktury (jinak nefunguje kontrola hashů - v souborech je celá relativní cesta!)
find . -type f
vypíše rekurzivně všechny soubory ve struktuře- parametr
-exec
zde nepoužívám, protože do hash souborů chci celou relativní cestu, nikoli jen název souboru (to se mi hodí při zálohování) - mmch. hezký popis příkazu
find
je zde
- skript je umístěný v
/usr/local/sbin
usr@srv:/zaloha# ls -R .: druhy.txt prvni.archived prvni.txt test_dir ./test_dir: dalsi ./test_dir/dalsi: treti.txt usr@srv:/zaloha# find . -type f | xargs /usr/local/sbin/mkhash.sh usr@srv:/zaloha# ls -R .: druhy.txt druhy.txt.hash prvni.archived prvni.txt prvni.txt.hash test_dir ./test_dir: dalsi ./test_dir/dalsi: treti.txt treti.txt.hash usr@srv:/zaloha# find . -path "./*.hash" | xargs xxh64sum -c ./prvni.txt: OK ./druhy.txt: OK ./test_dir/dalsi/treti.txt: OK
Diskuze