Sincroniza timestamps de arquivos idênticos entre árvores de diretórios?

1

Em janeiro de 2015, transferi alguns arquivos de uma imagem de backup criada por dd para um novo disco rígido. Essa transferência não preservou os timestamps, então, basicamente, todos os arquivos mostram um timestamp de 20 de janeiro.

Desde então, muitos arquivos foram modificados, novos arquivos foram criados, etc., mas muitos outros arquivos ainda são idênticos (exceto timestamp) às cópias na imagem dd.

Eu gostaria de recursivamente copiar os timestamps dos arquivos da imagem dd para os arquivos correspondentes no novo disco, mas somente se os arquivos forem idênticos (isto é, somente se os arquivos não tiverem sido modificados desde a cópia original).

Eu tentei várias coisas com rsync, touch, etc., mas não consegui descobrir. Eu estou pensando que algo como o seguinte psuedocode funcionaria, mas eu estou muito familiarizado com o script 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

Ou, talvez até melhor, uma vez que também funcionaria se o arquivo fosse movido desde a transferência, existe alguma maneira de processar a saída de jdupes -rO dd_image harddisk ?

Qualquer ajuda seria muito apreciada!

    
por jellopuddingstick 30.12.2015 / 21:13

1 resposta

0

Eu tive uma necessidade muito semelhante, então aqui está a minha solução.

Os scripts Bash podem ser um pouco complicados, especialmente quando se trata de nomes de arquivos com espaços, e se você fizer a coisa errada você pode acabar causando estragos, então é melhor dividir as coisas em pedaços gerenciáveis e testáveis.

Parte 1, um script que faz o comportamento necessário para apenas um arquivo:

#!/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"

Parte 2:

Use 'find' para fazer a descoberta recursiva dos arquivos, o que pode ser a parte complicada.

Isso também permite condições mais avançadas, incluindo a especificação da data de modificação, para que você possa evitar tocar em coisas que definitivamente não devem ser tocadas, por segurança e velocidade. Veja -mtime em man find .

Por exemplo, para localizar todos os arquivos com um carimbo de data e hora da última modificação de 1 ano atrás ou mais:

find "DEST_DIRECTORY" -type f -mtime +365

em que DEST_DIRECTORY é o diretório que você deseja corrigir. Marque esta opção para retornar os arquivos que você deseja corrigir.

Parte 3:

Combine as duas partes acima. Isso é um pouco complicado, devido à necessidade de passar dois arquivos diferentes para copy_timestamp_if_identical.sh , o que não é fácil com find e -exec . No final, decidi escrever um script de ajuda:

#!/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"

Você precisa passar os diretórios source e dest para ele, assim como o arquivo a ser modificado, assim a solução combinada se parece com:

find "DEST_DIR" -type f -mtime +365 -exec copy_timestamp_if_identical_helper.sh '{}' "SOURCE_DIR" "DEST_DIR" ';'
    
por 17.01.2016 / 00:13