私のサーバーの中央リポジトリに研究用ファイルのコレクションを構築しました。私は常にリポジトリを管理し、ディレクトリの名前を変更して移動し、ディレクトリのツリー構造を変更します。私はリポジトリ内のファイルのローカルコピーを常に更新して編集しています。これにより、リポジトリにクライアントの新しいファイルに置き換える必要があるファイルがありますが、ディレクトリツリーが変更される状況が発生します。
rsync
まだ学んでいないオプションはありますか?ディレクトリツリーを変更すると、rsyncが機能しないことがわかりました。私はテストしましたrsync --existing
それとも少しありますか?コマンドライン-fu使用find
してmv
?Webなどを検索してみてください。リソース検索のみを検索して置き換えるファイルにはい。
- アップデート1可能であれば、@meuhと@Lqueryvgに素晴らしい答えを提供します。 @css1971が彼の答えに追加され、ファイル管理を転覆させる強力なケースを作成したことを確認しました。残念ながら、時間が足りなくなり、報酬システムが私のお気に入りの答えを選びました。私はすべての答えが非常に有益であることがわかりました。みんなに感謝したいです。次の週末に、より思慮深い意見を提示できることを楽しみにしています。
答え1
[私のコメントからOPに拡張]。flat
すべてのファイルのコピーを含みますが、単純なリストにあるリポジトリにディレクトリを作成します。コピーはハードリンクなので、スペースを取らないでください。ローカルコンピュータでも同じことをしてください。その後、ローカルフラットディレクトリからリモートフラットディレクトリにrsyncできます。 rsyncを使用すると、リモートハードリンクが保存されるため、すべてのリモートファイルが更新されます--inplace
。フラットディレクトリはrsyncの前にスクリプトとして作成され、rsyncの後に削除できます。
以下は、実行可能な概念証明テストスクリプトです。
#!/bin/bash
dosync(){ # function to create flat trees and rsync them
mkdir flat
mkdir flatl
find repo -type f -exec ln {} flat \;
find local -type f -exec ln {} flatl \;
rsync -aHv --inplace flatl/ flat
rm -fr flat flatl
}
# create repo and local dirs with same content. 3 empty files
cd /tmp || exit
mkdir repo
( cd repo; touch a b c )
mkdir local
rsync -a repo/ local
dosync
echo hi >local/a # example change of local file a
dosync
mkdir repo/new # example move of repo file b
mv repo/b repo/new/
echo hello >local/b # change local file b
dosync
ls -lR repo local
# rm -fr flat flatl repo local
反対方向の場合、dosyncがローカル修正をリポジトリに転送した後、単にrm -fr local
「rsync -a repo / local」を使用してリポジトリ全体をローカルファイルシステムにコピーできます。代わりに、同様の技術を使用してリポジトリに転送する必要がある新しいファイルの数を減らすことができます。
reversesync(){
mkdir flat
mkdir flatl
find repo -type f -exec ln {} flat \;
find local -type f -exec ln {} flatl \;
mv flat repo/flat
mv flatl local/flat # not flatl!
rsync -aHv --delete repo/ local
rm -fr repo/flat local/flat
}
これにより、rsyncがハードリンクされたファイルを表示してコピーを回避できるように、フラット化されたツリーはそれぞれストレージとローカルディレクトリに移動されます。 (明らかに今回はフラットディレクトリの名前は同じでなければなりません)。
既知のファイルが変更されている場合は、リポジトリでfind
それを使用してツリーから新しい場所を取得し、そこからファイルを同期できます。たとえば、
file=mychangedfile.abc
to=$(find repo -name "$file")
from=$(find local -name "$file")
rsync -av "$from" "$to"
これはリポジトリがインストールされていると仮定しますssh repo find...
。そうでなければ、リポジトリでsshを使用できない場合は、rsyncを使用して仮想ローカルターゲットにファイルのリストを取得し、目的のファイルを抽出できます。
to=$(rsync -a --list-only repo dummy | awk '/\/'"$file"'$/{print $NF}')
答え2
私はrsyncがfindとmvのように間違ったツールだと思います。私の提案は、ソフトウェア構成管理システムを使用することです。これには、Subversion、Git、Mercurial、Bazaarなどが含まれます。どちらもツリー構造の変更を簡単に処理できます。
説明する構造には、クライアントシステムにツリー構造Aがあり、セカンダリロケーション(ローカルでもリモートでも)にストレージツリー構造Bがあります。
両方を更新した場合は、競合する変更を適用する必要があります。正しい順序で両方のリポジトリを一貫して維持します。順番に適用されないと、構造が存在しなくなるため、ある構造への変更を他の構造に直接適用できない状況が発生します。
現時点では、両方のリポジトリを一貫して作成するためにどの変更を適用する必要があるのかを自動的に知ることができるrsyncオプションはありません。それはそれのために設計されていません。あるリポジトリが他のリポジトリと同じように見えるようにすることはできますが、一度に片側だけを変更するだけです。たとえば、A、B、Aを交互に変更します。いつでもファブリックAまたはBのいずれかをマスターとして指定し、変更を同期する必要があります。一方向のみ一度。
私はまた、あなたが探している結果を達成する単純なcommandline-fuコマンドがあると信じていないので、今あなたはシェルプログラミング領域にいます。
あなただけが変わったらツリー構造Bとのみ文書内容Aが変更されたファイルのファイル名を見つけ、Bからそのファイルの新しいパスを取得し、一致するようにAのツリー構造を変更するのは比較的簡単です。これただファイル名が一意の場合は有効です。
Aの構造をBと一致させる擬似コードは次のとおりです。
generate list of file names in A and their paths
For each of the names in A
find that same name in B
If the path of A is the same as B
continue to the next file
if not then
create the directory structure in A
move the file to the new location.
if the old path in A is now empty
delete the directory.
repeat
check if the parent directory is now empty, then delete it.
until a non empty directory
ツリー構造が同期されると、AはBのまったく同じパスに直接コピーできます。 rsyncの--updateオプションを使用すると、古いファイルを新しいファイルで双方向に上書きできます。
ファイル名セレクタとして find を使用してローカルに変更されたファイルを既存のリポジトリにコピーするいくつかのサンプルシェルコード。
#!/bin/bash
set -xv
localRepo=/tmp/a
remoteRepo=/tmp/b
rm -rf $localRepo $remoteRepo
mkdir -p $localRepo/1/2/ $localRepo/1/3/
mkdir -p $remoteRepo/2/1/ $remoteRepo/3/1/
echo a12 > $localRepo/1/2/file
echo b21 > $remoteRepo/2/1/file
echo a13 > $localRepo/1/3/file1
echo b31 > $remoteRepo/3/1/file1
echo ex1
cat $localRepo/1/2/file $remoteRepo/2/1/file
echo ex2
cat $localRepo/1/3/file1 $remoteRepo/3/1/file1
localFileNameList=$(find $localRepo -type f -mtime -1 | xargs -L 1 basename)
for localFileName in $localFileNameList
do
localFilePath=$(find $localRepo -name $localFileName | xargs dirname)
backFile=$(find $remoteRepo -name $localFileName)
repoDir=$(dirname $backFile)
cp $localFilePath/$localFileName $repoDir
done
echo ex1
cat $localRepo/1/2/file $remoteRepo/2/1/file
echo ex2
cat $localRepo/1/3/file1 $remoteRepo/3/1/file1
たとえば、使いやすいSCMの1つであるSubversionにファイルシステムをインポートするには、次の手順を実行します。
e.g.
mkdir /tmp/svn
svnadmin create /tmp/svn/reponame
cd /tmp/b
svn import -m "The initial import " file:///tmp/svn/reponame
Adding 2
Adding 2/1
Adding 2/1/file
Adding 3
Adding 3/1
Adding 3/1/file1
その後、リポジトリを確認してローカルを変更します。
$ cd /tmp
$ svn checkout file:///tmp/svn/reponame
A reponame/2
A reponame/2/1
A reponame/2/1/file
A reponame/3
A reponame/3/1
A reponame/3/1/file1
Checked out revision 1.
/tmp:
$ cd reponame/
/tmp/reponame:
$ ls -ltr
total 8
drwxrwxr-x 3 css1971 css1971 4096 Apr 11 12:04 3
drwxrwxr-x 3 css1971 css1971 4096 Apr 11 12:04 2
/tmp/reponame:
$ svn move 3 4
A 4
D 3
D 3/1
D 3/1/file1
/tmp/reponame:
変更をリポジトリに再コミットします。
$ svn commit -m "renamed dir"
Deleting 3
Adding 4
Committed revision 2.
この時点から、svnツールを使用して一般的なワークフローの一部としてリポジトリを操作します。
便利なコマンド:
svn import
svn update
svn commit
svn del
svn cp
svn mv
コマンドリファレンス: http://svnbook.red-bean.com/en/1.7/svn.ref.html
答え3
仕事だと思います。調和!私は何年もプレイしていませんが、あなたが要求するものとまったく一致すると思います...ホームページには次のように書かれています。
Unisonは、OSX、Unix、およびWindows用のファイル同期ツールです。これにより、ファイルとディレクトリのコレクションの2つのコピーを別のホスト(または同じホスト上の別のディスク)に保存して別々に変更し、各コピーの変更を別のコピーに伝播して更新できます。
見て続けてニュースをお伝えください! ;)
答え4
あなたは絶対にできるディレクトリ構造の変更を実行し、rsync
あなたが知らないかもしれないいくつかの興味深いオプション、特に-H
ハードリンクを保存するオプションがあります。
私自身のシナリオを説明します。これはあなたに効果があるかもしれませんが、少なくともあなたがそれを探してください。興味深い。
想像する:
rsync
他のディレクトリ(リモートシステムや外部ディスクなど)にコピーされるディレクトリツリーには、多くのファイルを含む大きなディレクトリがあります。
ディレクトリを再構成し、ファイルの名前を変更したり、ファイルを別のサブディレクトリに移動したいのですが、ファイル自体の内容は変更したくありません。
ただし、次回実行時に移動されたファイルrsync
名または名前が変更されたすべてのファイルのデータが再コピーされます。そのファイルがすでにターゲットに存在しています(他の場所にあるにもかかわらず)。データを再コピーせずにファイルの場所を同期する方法は次のとおりです。クイック。
明らかにテストシステムで最初に試してみました注意してくださいあなたのデータとして。
ソースデータがにあり、/tmp/src/dir/
ターゲットレプリカがにあるとします/tmp/dst/
。これはリモートrsync
ターゲットでも機能します。
0.
設定例:
$ mkdir -p /tmp/src/dir; cd $_
$ fallocate -l 1000 a
$ fallocate -l 1000 b
$ fallocate -l 1000 c
$ tree /tmp/src
/tmp/src
`-- dir
|-- a
|-- b
`-- c
1.
初期コピー:
$ mkdir /tmp/dst; rsync -havHP /tmp/src/dir /tmp/dst
この時点で、/tmp/src/dir/
その中にあるすべてのファイルとディレクトリが/tmp/dst/
。
$ tree /tmp/dst
/tmp/dst
`-- dir
|-- a
|-- b
`-- c
2.
ソース内のディレクトリ構造のハードリンクコピーを作成します。注:これは、ファイルやディレクトリが多い場合でも同様です。まもなく、メタデータのみコピーするためです。
$ cd /tmp/src/; mv dir dir.old
$ cp -rlp dir.old dir
# -l = link not copy
# -p = preserve permissions etc
三。
/tmp/src/dir
ファイルの移動や名前の変更など、から多くの変更を行います。この例では、すべてのファイルを新しいサブディレクトリに移動します。
$ cd /tmp/src/dir; mkdir sub
$ mv a b c sub
$ tree /tmp/src/dir
/tmp/src/dir
`-- sub
|-- a
|-- b
`-- c
4.
古いディレクトリ構造と新しいディレクトリ構造を変更した後、rsync
ターゲットの横にクイック、ターゲットのハードリンクのみコピーするため、ファイルの内容が変更されない限りデータはコピーされません。
$ cd /tmp/src
$ mv dir dir.new; mv dir.old dir
$ rsync -havHP --delete-after --no-inc-recursive \
/tmp/src/dir /tmp/src/dir.new /tmp/dst
rsyncの出力は、ファイルの内容を再送信しないことを示しています。
building file list ...
9 files to consider
dir.new/
dir.new/sub/
dir.new/sub/a => dir/a
dir.new/sub/b => dir/b
dir.new/sub/c => dir/c
sent 165 bytes received 45 bytes 420.00 bytes/sec
total size is 6.00K speedup is 28.57
5.
最後に、ソースとターゲットの両方で、ソースコンテンツを新しいコンテンツに置き換えてクリーンアップdir
します。dir.new
$ cd /tmp/src
$ rm -rf dir
$ mv dir.new dir
$ cd /tmp/dst
$ rm -rf dir
$ mv dir.new dir
上記の回避策はやや面倒で、ディレクトリ交換中に他の人がデータにアクセスすることに注意する必要がありますが、rsync
場合によっては多くの時間を節約できる興味深い機能であることは明らかです。