2008-09-24 2 views
2

У меня есть компьютер A с двумя деревьями каталогов. Первый каталог содержит исходные даты мод, которые охватывают несколько лет. Второй каталог - это копия первого с несколькими дополнительными файлами. Существует второй компьютер, который содержит дерево каталогов, которое совпадает со вторым каталогом на компьютере A (новые времена модификации и дополнительные файлы). Как обновить файлы в двух более новых каталогах на обеих машинах, чтобы модные файлы в файлах совпадали с оригиналом? Обратите внимание, что эти деревья каталогов составляют порядка 10 гигабайт, поэтому решение должно включать некоторый метод отправки только информации о дате на второй компьютер.Синхронизация времени модификации файла через несколько каталогов

ответ

0

Я думаю Rsync (с нужными опциями) будет делать это - он утверждает только отправлять различия между файлами, поэтому предположительно отработать, что нет разницы подлежащих передаче.

- время сохраняет время модификации, которое вы хотите.

См (например) http://linux.die.net/man/1/rsync

Кроме того, добавить -I, --ignore раза не пропускать файлы, которые соответствуют размеру и время

так, что все файлы «переданы» и доверие к оптимизация различия файлов Rsync, чтобы сделать это «довольно эффективным» - см. отрывок из человека странице ниже

-t, --times Это говорит Rsync передавать время модификации вместе с файлами и обновлять их на пульте дистанционного управления сист Эм. Обратите внимание: если этот параметр не используется, оптимизация, исключающая файлы, которые не были изменены, не может быть эффективной; другими словами, отсутствующий -t или -a приведет к тому, что следующая передача будет вести себя так, как если бы она использовалась -I, в результате чего все файлы были обновлены (хотя алгоритм rsync сделает обновление достаточно эффективным, если файлы фактически не изменились , вам гораздо лучше использовать -t).

+0

Фактически rsync использует дату/время, чтобы решить, существуют ли различия (он только синхронизирует файлы с более новым модом дата локально, чем удаленная); вы не можете использовать rsync для этого. Кроме того, rsync ничего не синхронизирует, если не решит также синхронизировать содержимое файла, и это исключает вопросник. – Mecki 2008-09-24 17:08:14

1

Я бы просмотрел все файлы в дереве исходного каталога и собрал время модификации из них в сценарий, который мог бы работать на других деревьях каталогов. Вам нужно быть осторожным в отношении нескольких «ошибок». Во-первых, убедитесь, что ваш выходной скрипт имеет относительные пути и убедитесь, что вы запустили его из соответствующего целевого каталога, который должен быть корневым каталогом целевого дерева. Кроме того, при смене машин убедитесь, что вы используете тот же часовой пояс, что и на машине, где вы создали сценарий.

Вот сценарий Perl, который я собираю, который выведет команды touch, необходимые для обновления времени на других деревьях каталогов. В зависимости от целевых компьютеров вам может потребоваться настроить форматы даты или параметры команды, но это должно дать вам место для запуска.

#!/usr/bin/perl 

my $STARTDIR="$HOME/test"; 

chdir $STARTDIR; 
my @files = `find . -type f`; 
chomp @files; 

foreach my $file (@files) { 
    my $mtime = localtime((stat($file))[9]); 
    print qq(touch -m -d "$mtime" "$file"\n); 
} 
1

Другой подход, вы можете попробовать это присоединить удаленный каталог с помощью NFS, а затем скопировать раз используя find и touch -r.

2

Следующая команда будет убедиться, что TEST2 получает ту же дату, назначенную что TEST1 имеет

touch -t `stat -t '%Y%m%d%H%M.%S' -f '%Sa' TEST1` TEST2 

Теперь вместо использования жестко закодированных значений здесь, вы можете найти файлы с помощью «найти» утилиту, а затем запустить коснитесь SSH на удаленной машине. Однако это означает, что вам может потребоваться ввести пароль для каждого файла, если вы не переключите SSH на аутентификацию сертификата.Я бы предпочел не делать все это в супермощном однострочном лайнере. Вместо этого давайте работать с временными файлами. Сначала перейдите в соответствующий каталог и запустите find (вы можете фильтровать по типу файла, размеру, расширению, что угодно вам, см. «Man find» для деталей. Я просто фильтрую файл типа здесь, чтобы исключить любые каталоги):

find . -type f -print -exec stat -t '%Y%m%d%H%M.%S' -f '%Sm' "{}" \; > /tmp/original_dates.txt 

Теперь у нас есть файл, который выглядит следующим образом (в моем примере есть только две записи там):

# cat /tmp/original_dates.txt 
./test1 
200809241840.55 
./test2 
200809241849.56 

Теперь просто скопируйте файл на другую машину и поместить его в (поэтому соответствующие пути к файлам соответствуют) и применять даты:

cat original_dates.txt | (while read FILE && read DATE; do touch -t $DATE "$FILE"; done) 

Будет также работать с именами файлов, содержащими пробелы.

Одно примечание: я использовал последнюю дату «модификации» в stat, так как это то, что вы написали в вопросе. Однако это скорее похоже на то, что вы хотите использовать дату создания (каждый файл имеет дату создания, дату последней модификации и дату последнего доступа), вам нужно немного изменить вызов stat.

'%Sm' - last modification date 
'%Sc' - creation date 
'%Sa' - last access date 

Однако прикосновение может изменить только время модификации и время доступа, я думаю, что это не может изменить время создания файла ... так что, если это было ваше реальное намерение, мое решение может быть суб- оптимальный ... но в этом случае ваш вопрос был также ;-)

+0

Мне пришлось использовать touch new_file -t \ `date -d @ \\` stat -t -c "% Y" old_file \\ `+% Y% m% d% H% M.% S \` – kormoc 2012-06-06 21:23:02

2

Ответ отчасти частично верный, rsync способен сделать это, однако с разными параметрами. Правильная команда

rsync -Prt --size-only original_dir copy_dir 

где -P позволяет частичные переводы и отображает индикатор прогресса, -r через подкаталоги рекурсивно, -t сохраняет временные метки и --size-only не передавать файлы, которые соответствуют по размеру.

0

Вместо этого я использовал следующие сценарии Python.

Сценарии Python работают намного быстрее, чем подход, создающий новые процессы для каждого файла (например, с использованием find и stat). Решение ниже также работает в случае разницы в часовых поясах между системами, так как используется время UTC. Он также работает с путями, содержащими пробелы (но не для путей, содержащих новую строку!). Он не устанавливает времен для символических ссылок, потому что the operating system provides no mechanism to modify the timestamp of a symlink, но в файловом менеджере время файла, на которое указывает ссылка символической ссылки, отображается в любом случае. Он использует параметр maxTime, чтобы избежать сброса дат для файлов, которые фактически изменены после копирования из исходного каталога.

listMTimes.py:

import os 
from datetime import datetime 
from pytz import utc 

for dirpath, dirnames, filenames in os.walk('./'): 
    for name in filenames+dirnames: 
     path = os.path.join(dirpath, name) 
     # Avoid symlinks because os.path.getmtime and os.utime get and 
     # set the time of the pointed file, and in the new directory, 
     # the link may have been redirected. 
     if not os.path.islink(path): 
      mtime = datetime.fromtimestamp(os.path.getmtime(path), utc) 
      print(mtime.isoformat()+" "+path) 

setMTimes.ру:

import datetime, fileinput, os, sys, time 
import dateutil.parser 
from pytz import utc 

# Based on 
# http://stackoverflow.com/questions/6999726/python-getting-millis-since-epoch-from-datetime 
def unix_time(dt): 
    epoch = datetime.datetime.fromtimestamp(0, utc) 
    delta = dt - epoch 
    return delta.total_seconds() 

if len(sys.argv) != 2: 
    print('Syntax: '+sys.argv[0]+' <maxTime>') 
    print(' where <maxTime> an ISO time, e. g. "2013-12-02T23:00+02:00".') 
    exit(1) 

# A file with modification time newer than maxTime is not reset to 
# its original modification time. 
maxTime = unix_time(dateutil.parser.parse(sys.argv[1])) 

for line in fileinput.input([]): 
    (datetimeString, path) = line.rstrip('\r\n').split(' ', 1) 
    mtime = dateutil.parser.parse(datetimeString) 
    if os.path.exists(path) and not os.path.islink(path): 
     if os.path.getmtime(path) <= maxTime: 
      os.utime(path, (time.time(), unix_time(mtime))) 

Использование: в первом каталоге (оригинал) запустить

python listMTimes.py >/tmp/original_dates.txt 

Затем во второй директории (копия оригинала, возможно, с некоторыми файлы, измененные/добавленные/удалено) выполните следующее:

python setMTimes.py 2013-12-02T23:00+02:00 </tmp/original_dates.txt 
Смежные вопросы