4

我有一台带有两个目录树的计算机 A。第一个目录包含可以追溯到几年前的原始 mod 日期。第二个目录是第一个目录的副本,其中包含一些附加文件。有第二台计算机包含一个目录树,该目录树与计算机 A 上的第二个目录相同(新的修改时间和附加文件)。如何更新两台机器上两个较新目录中的文件,以使文件上的修改时间与原始文件相同?请注意,这些目录树大约为 10 GB,因此解决方案必须包括一些仅将日期信息发送到第二台计算机的方法。

4

6 回答 6

3

保罗的回答部分正确,rsync能够做到这一点,但参数不同。正确的命令是

rsync -Prt --size-only original_dir copy_dir

where-P启用部分传输并显示进度指示器,-r通过子目录递归,-t保留时间戳并且--size-only不传输大小匹配的文件。

于 2013-05-20T10:36:07.743 回答
2

以下命令将确保 TEST2 获得与 TEST1 相同的日期

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

现在,您可以使用“查找”实用程序查找文件,然后在远程计算机上通过 SSH 运行 touch,而不是在这里使用硬编码值。但是,这意味着您可能必须为每个文件输入密码,除非您将 SSH 切换到证书身份验证。我宁愿不要在一个超级花哨的单衬里做这一切。相反,让我们使用临时文件。首先转到有问题的目录并运行查找(您可以按文件类型、大小、扩展名进行过滤,无论您喜欢什么,有关详细信息,请参阅“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

但是,触摸只能改变修改时间和访问时间,我认为它不能改变文件的创建时间......所以如果这是你的真正意图,我的解决方案可能不是最佳的......但在那如果你的问题也是;-)

于 2008-09-24T17:06:27.857 回答
1

I would go through all the files in the source directory tree and gather the modification times from them into a script that I could run on the other directory trees. You will need to be careful about a few 'gotchas'. First, make sure that your output script has relative paths, and make sure you run it from the proper target directory, which should be the root directory of the target tree. Also, when changing machines make sure you are using the same timezone as you were on the machine where you generated the script.

Here's a Perl script I put together that will output the touch commands needed to update the times on the other directory trees. Depending on the target machines, you may need to tweak the date formats or command options, but this should give you a place to start.

#!/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);
}
于 2008-09-24T16:48:13.437 回答
1

The other approach you could try is to attach the remote directory using NFS and then copy the times using find and touch -r.

于 2008-09-24T16:50:28.953 回答
0

I think rsync (with the right options) will do this - it claims to only send file differences, so presumably will work out that there are no differences to be transferred.

--times preserves the modification times, which is what you want.

See (for instance) http://linux.die.net/man/1/rsync

Also add -I, --ignore-times don't skip files that match size and time

so that all files are "transferred' and trust to rsync's file differences optimisation to make it "fairly efficient" - see excerpt from the man page below.

-t, --times This tells rsync to transfer modification times along with the files and update them on the remote system. Note that if this option is not used, the optimization that excludes files that have not been modified cannot be effective; in other words, a missing -t or -a will cause the next transfer to behave as if it used -I, causing all files to be updated (though the rsync algorithm will make the update fairly efficient if the files haven't actually changed, you're much better off using -t).

于 2008-09-24T16:47:41.787 回答
0

我改用了以下 Python 脚本。

Python 脚本的运行速度比为每个文件创建新进程的方法(如使用findand stat)快得多。下面的解决方案也适用于系统之间的时区差异,因为它使用 UTC 时间。它也适用于包含空格的路径(但不适用于包含换行符的路径!)。它没有为符号链接设置时间,因为操作系统没有提供修改符号链接时间戳的机制,但是在文件管理器中,符号链接指向的文件的时间无论如何都会显示。它使用一个maxTime参数来避免重置从原始目录复制后实际修改的文件的日期。

listMTim​​es.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)

setMTim​​es.py:

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
于 2013-12-04T14:49:21.527 回答