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 v ahoj.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 a print $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 soubor ahoj.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

Vložte svůj komentář. Používání wiki syntaxe povoleno: