2 つのディレクトリ ツリーを持つコンピューター A があります。最初のディレクトリには、数年前にさかのぼる元の mod の日付が含まれています。2 番目のディレクトリは、いくつかの追加ファイルを含む最初のディレクトリのコピーです。コンピューター A の 2 番目のディレクトリと同じディレクトリ ツリーを含む 2 番目のコンピューター be があります (新しい mod 時間と追加のファイル)。ファイルの mod 時刻が元のファイルと同じになるように、両方のマシンの 2 つの新しいディレクトリにあるファイルを更新するにはどうすればよいですか? これらのディレクトリ ツリーは数十ギガバイトのオーダーであるため、日付情報のみを 2 台目のコンピュータに送信する方法をソリューションに含める必要があることに注意してください。
6 に答える
ポールによる答えは部分的に正しいですが、rsync
これを行うことができますが、パラメーターが異なります。正しいコマンドは
rsync -Prt --size-only original_dir copy_dir
where-P
は、部分転送を有効にし、進行状況インジケーターを表示し、-r
サブディレクトリを再帰的に処理し、-t
タイム スタンプを保持--size-only
し、サイズが一致するファイルを転送しません。
次のコマンドは、TEST2 が TEST1 に割り当てられたのと同じ日付を取得することを確認します。
touch -t `stat -t '%Y%m%d%H%M.%S' -f '%Sa' TEST1` TEST2
ここでハードコードされた値を使用する代わりに、「find」ユーティリティを使用してファイルを見つけ、リモート マシンで SSH 経由で touch を実行できます。ただし、SSH を証明書認証に切り替えない限り、ファイルごとにパスワードを入力する必要がある場合があります。超派手なワンライナーですべてをやりたくありません。代わりに、一時ファイルを操作しましょう。最初に問題のディレクトリに移動し、検索を実行します (ファイルの種類、サイズ、拡張子など、好きなものでフィルタリングできます。詳細については、「man find」を参照してください。ここでは、ディレクトリを除外するためにファイルの種類でフィルタリングしています)。
find . -type f -print -exec stat -t '%Y%m%d%H%M.%S' -f '%Sm' "{}" \; > /tmp/original_dates.txt
これで、次のようなファイルができました (私の例では、2 つのエントリしかありません)。
# 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)
スペースを含むファイル名でも機能します。
1つのメモ:あなたが質問に書いたものであるため、統計で最後の「変更」日付を使用しました。ただし、「作成」日 (すべてのファイルには作成日、最終変更日、最終アクセス日があります) を使用したいように聞こえますが、stat 呼び出しを少し変更する必要があります。
'%Sm' - last modification date
'%Sc' - creation date
'%Sa' - last access date
ただし、タッチは変更時間とアクセス時間しか変更できません。ファイルの作成時間を変更することはできないと思います...それがあなたの本当の意図である場合、私の解決策は最適ではないかもしれません...しかし、その点であなたの質問もそうでした;-)
ソース ディレクトリ ツリー内のすべてのファイルを調べて、それらから変更時間を収集し、他のディレクトリ ツリーで実行できるスクリプトにします。いくつかの「落とし穴」に注意する必要があります。まず、出力スクリプトに相対パスがあることを確認し、適切なターゲット ディレクトリ (ターゲット ツリーのルート ディレクトリである必要があります) から実行していることを確認してください。また、マシンを変更するときは、スクリプトを生成したマシンと同じタイムゾーンを使用していることを確認してください。
touch
これは、他のディレクトリ ツリーの時刻を更新するために必要なコマンドを出力する、私がまとめた Perl スクリプトです。ターゲット マシンによっては、日付形式やコマンド オプションを微調整する必要がある場合がありますが、これで開始できるはずです。
#!/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
ます。
rsync(適切なオプションを使用)がこれを行うと思います-ファイルの違いのみを送信すると主張しているため、おそらく転送する違いがないことがわかります。
--times は、変更時刻を保持します。これは、必要なものです。
(たとえば) http://linux.die.net/man/1/rsyncを参照してください
また、-I、--ignore-times を追加して、サイズと時刻が一致するファイルをスキップしません
すべてのファイルが「転送」され、rsync のファイル差分最適化を信頼して「かなり効率的」にするようにします。以下の man ページからの抜粋を参照してください。
-t, --times これは、rsync に変更時刻をファイルとともに転送し、リモート システムで更新するように指示します。このオプションを使用しないと、変更されていないファイルを除外する最適化が有効にならないことに注意してください。つまり、-t または -a がない場合、次の転送は -I を使用したかのように動作し、すべてのファイルが更新されます (ただし、ファイルが実際に変更されていない場合、rsync アルゴリズムにより更新がかなり効率的になります)。 、-tを使用する方がはるかに優れています)。
代わりに、次の Python スクリプトを使用しました。
Python スクリプトは、ファイルごとに新しいプロセスを作成する方法 ( や を使用するfind
などstat
) よりもはるかに高速に実行されます。以下のソリューションは、UTC 時間を使用するため、システム間でタイムゾーンが異なる場合にも機能します。また、スペースを含むパスでも機能します (ただし、改行を含むパスでは機能しません!)。オペレーティングシステムは 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.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
次に、2 番目のディレクトリ (元のコピーで、一部のファイルが変更/追加/削除されている可能性があります) で、次のように実行します。
python setMTimes.py 2013-12-02T23:00+02:00 </tmp/original_dates.txt