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.checkxxh64sum -c ahoj.check- tady se provede kontrola, zda soubor vahoj.checkexistuje 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.hashvypíše seznam změněných souborů -F:říká, že oddělovačem pro awk bude dvojtečka aprint $1zase ž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.txtjiž 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 fvypíše rekurzivně všechny soubory ve struktuře- parametr
-execzde 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
findje 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