Zsynchronizować znaczniki czasowe identycznych plików między drzewami katalogów?

1

W styczniu 2015 r. Przesłałem niektóre pliki z utworzonego obrazu kopii zapasowej na nowy dysk twardy. Ten transfer nie zachował znaczników czasu, więc w zasadzie każdy plik zawiera znacznik czasu z 20 stycznia.

Od tego czasu wiele plików zostało zmodyfikowanych, nowe pliki zostały utworzone itp., Ale wiele innych plików jest nadal identycznych (oprócz sygnatury czasowej) z kopiami na obrazie dd.

Chciałbym rekurencyjnie kopiować znaczniki czasu z plików obrazu dd do pasujących plików na nowym dysku, ale tylko wtedy, gdy pliki są identyczne (tj. Tylko jeśli pliki nie zostały zmodyfikowane od czasu oryginalnej kopii).

Próbowałem różnych rzeczy z rsync, dotykiem itp., Ale nie byłem w stanie tego rozgryźć. Myślę, że coś takiego jak poniższy kod psuedocode zadziała, ale jestem bardzo obeznany ze skryptami bash.

for each file_in_dd_image
if (md5sum(file_in_dd_image) == md5sum(file_on_harddisk))
touch file_on_harddisk --reference=file_in_dd_image

A może nawet lepiej, ponieważ działałoby to również, jeśli plik został przeniesiony od czasu przeniesienia, czy istnieje jakiś sposób na przetworzenie danych wyjściowych jdupes -rO dd_image harddisk?

Każda pomoc byłaby bardzo mile widziana!

jellopuddingstick
źródło
Możesz użyć narzędzia unisonz timesprzełącznikiem. Zsynchronizuje znaczniki czasowe plików. Jednak nie ustawi znaczników czasu katalogu.
Giorgio

Odpowiedzi:

0

Miałem bardzo podobną potrzebę, więc oto moje rozwiązanie.

Skrypty Bash mogą być nieco trudne, szczególnie jeśli chodzi o nazwy plików ze spacjami, a jeśli zrobisz coś złego, możesz spowodować spustoszenie, więc najlepiej podzielić rzeczy na łatwe do kontrolowania, sprawdzalne elementy.

Część 1: skrypt, który wykonuje wymagane zachowanie tylko dla jednego pliku:

#!/bin/bash

# Usage: copy_timestamp_if_identical.sh source_file dest_file

test "$#" -eq 2 || { echo "Wrong number of arguments" >&2; exit 1; }

FILE1="$1"
FILE2="$2"

test -f "$FILE1" || { echo "File \"$FILE1\" not found"  >&2; exit 1; }
test -f "$FILE2" || { echo "File \"$FILE2\" not found"  >&2; exit 1; }

if test "$(basename "$FILE1")" != "$(basename "$FILE2")";
then
    # Not same filename
    exit;
fi

if test $(md5sum "$FILE1" | cut -d ' ' -f 1) != $(md5sum "$FILE2" | cut -d ' ' -f 1);
then
    # Not same contents
    exit;
fi

echo "Updating \"$FILE2\" from \"$FILE1\""
touch -r "$FILE1" "$FILE2"

Część 2:

Użyj polecenia „znajdź”, aby wykonać rekurencyjne wyszukiwanie plików, co może być trudną częścią.

Umożliwia to również bardziej zaawansowane warunki, w tym określenie daty modyfikacji, dzięki czemu można uniknąć dotykania rzeczy, których zdecydowanie nie należy dotykać, ze względu na bezpieczeństwo i szybkość. Zobacz -mtimew man find.

Na przykład, aby znaleźć wszystkie pliki z datą ostatniej modyfikacji znaczącą 1 rok temu lub więcej:

find "DEST_DIRECTORY" -type f -mtime +365

gdzie DEST_DIRECTORY to katalog, który chcesz naprawić. Zaznacz, że zwraca pliki, które chcesz naprawić.

Część 3:

Połącz powyższe dwie części. Jest to nieco trudne, ponieważ trzeba przekazać dwa różne pliki copy_timestamp_if_identical.sh, co nie jest łatwe przy pomocy findi -exec. W końcu postanowiłem napisać skrypt pomocniczy:

#!/bin/bash

# Usage: copy_timestamp_if_identical_helper.sh file_in_dest_dir source_dir dest_dir

test "$#" -eq 3 || { echo "Wrong number of arguments" >&2; exit 1; }

DEST_FILE="$1"
SRC_DIR="$2"
DEST_DIR="$3"

SRC_FILE="$SRC_DIR${DEST_FILE:${#DEST_DIR}}"

echo copy_timestamp_if_identical.sh "$SRC_FILE" "$DEST_FILE"

Musisz przekazać do niego katalog źródłowy i docelowy, a także plik do modyfikacji, więc połączone rozwiązanie wygląda następująco:

find "DEST_DIR" -type f -mtime +365 -exec copy_timestamp_if_identical_helper.sh '{}' "SOURCE_DIR" "DEST_DIR" ';'
spookylukey
źródło