Rsyncフィルター:1つのパターンのみをコピーする


128

LaTeXからコンパイルされたすべてのPDFのみを格納するディレクトリを作成しようとしています。私はそれぞれのプロジェクトを別々のフォルダーに入れておくのが好きで、すべてがという大きなフォルダーに収められていますLaTeX。だから私は実行してみました:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

ですべてのpdfを見つけ~/LaTeX/て、出力フォルダーに転送します。これは機能しません。「*.pdf」に一致するものがないことがわかります。このフィルターを省略した場合、コマンドはLaTeXの下のすべてのプロジェクトフォルダー内のすべてのファイルを一覧表示します。したがって、*。pdfフィルターの問題です。~/ホームディレクトリへのフルパスに置き換えようとしましたが、効果はありませんでした。

私は、zshを使用しています。私はbashであっても同じことをやってみました、すべてのサブディレクトリ内のすべてのファイルを1つだけ表示されるフィルタ...ここで何が起こっているの?

rsyncがPDFのみのフィルターを理解しないのはなぜですか?


OK。更新:いいえ

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

これにより、ファイルリスト全体が表示されます。すべてが最初のパターンと一致するためだと思います...


ええ、あなたは正しいようです... **しかし、私の答えは(zshのパターンを使用して)うまくいくと思います。
マルセルスティムバーグ

回答:


248

TL、DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsyncはソースを宛先にコピーします。*.pdfソースとして渡すと、シェルはこれを.pdf現在のディレクトリ内の拡張子を持つファイルのリストに展開します。ソースとしてディレクトリを渡さなかったため、再帰的なトラバーサルは発生しません。

したがってrsync -a ~/LaTeX/ ~/Output/、rsyncに.pdfファイルのみをコピーするように指示するフィルターを使用して、を実行する必要があります。Rsyncのフィルタールールは、マニュアルを読むと気が遠くなるように見えますが、いくつかの簡単なルールで多くの例を構築できます。

  • 包含および除外:

    • ファイルを名前または場所で除外するのは簡単です:--exclude=*~--exclude=/some/relative/location(ソース引数に関連して、例えばこれは除外します~/LaTeX/some/relative/location)。
    • いくつかのファイルまたは場所のみを一致させたい場合は、それらを含め、それらにつながるすべてのディレクトリを含めて(たとえば、--include=*/)、残りを除外し--exclude='*'ます。それの訳は:
    • ディレクトリを除外すると、その下のすべてが除外されます。除外されたファイルはまったく考慮されません。
    • ディレクトリを含めると、その内容は自動的に含まれません。最近のバージョンで--include='directory/***'は、それを行います。
    • 各ファイルには、最初の一致ルールが適用されます(一致しないものはすべて含まれます)。
  • パターン:

    • パターンにが含まれていない場合は/、ファイル名sansディレクトリに適用されます。
    • パターンがで終わる場合、/ディレクトリにのみ適用されます。
    • パターンがで始まる場合、/引数としてに渡されたディレクトリからのパス全体に適用されますrsync
    • *単一のディレクトリコンポーネントの部分文字列(つまり、一致しない/)。**任意のパス部分文字列に一致します。
  • ソース引数がで終わる場合/、その内容がコピーされます(ごとにrsync -r a/ b作成さb/fooれますa/foo)。そうでない場合、ディレクトリ自体がコピーされます(rsync -r a b作成b/a)。


したがって、ここでは*.pdf、それらを含むディレクトリを含め、他のすべてを除外する必要があります。

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

これにより、一致するファイルやディレクトリを含むサブディレクトリが含まれていないディレクトリも含め、すべてのディレクトリがコピーされることに注意してください。これは--prune-empty-dirsオプションで回避できます(明示的に一致させてもディレクトリをコピーできないため、普遍的なソリューションではありませんが、それはまれな要件です)。

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

私のソリューション(zshの**パターンを使用)とは対照的に、これはターゲットディレクトリにディレクトリ構造を再作成します。私は...これはOPが何を望んでいるかどうかわからない
マルセルStimberg

1つのディレクトリのみを含め、/etc/lsyncd/lsyncd.conf.luaファイル内のすべてのディレクトリの残りを除外したい。何かアイデアがありますか?
ダダックミテシュ

@DhadukMitesh私はlsyncdに慣れていません。これは新しい質問として尋ねてください。
ジル

25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

デフォルトではすべてを含めるため、転送するファイルを含めた後にすべてを明示的に除外する必要があります。--dry-runを削除して、実際にファイルを転送します。

で始まる場合:

--exclude '*' --include '*.pdf'

次に、貪欲なマッチングにより、すべてがすぐに除外されます。

あなたがしようとした場合:

--include '*.pdf' --exclude '*' 

次に、最上位フォルダー内のpdfファイルのみが転送されます。ディレクトリは「*」で除外されているため、ディレクトリには続きません。


2
2014-03-17現在、これが最良の回答です。元のポスターの質問を正確に解決します。投票してください!追加--prune-empty-dirs(またはショートカット-m)すると、宛先で多くの空のディレクトリを節約することさえできますが、もちろん、それらはリマインダーまたは構造的な青写真として必要です。
ポーグ14年

1
ベストアンサー、-include = "* /"が重要です。
マーティンコニテック

1つのディレクトリのみを含め、/etc/lsyncd/lsyncd.conf.luaファイル内のすべてのディレクトリの残りを除外したい。何かアイデアがありますか?
ダダックミテシュ

15

のようなパターンを使用する場合*.pdf、シェルはそのパターンを「拡張」します。つまり、パターンを現在のディレクトリ内のすべての一致で置き換えます。実行しているコマンド(この場合はrsync)は、パターンを使用しようとしたことを認識していません。

ただし、zshを使用している場合、簡単な解決策があります。**パターンを使用して、フォルダーを再帰的に一致させることができます。これを試して:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/

それは現在のディレクトリ内のどこかからのすべてのpdf 〜/ LaTeX /から〜/ Output までのすべてをコピーしませんか?
SamB

私はあなたが意味したと思いますrsync -avn ~/LaTeX/**/*.pdf ~/Outputが、とのソリューション--includeはとにかくスケーラブルです。
アダムByrtek

申し訳ありませんが、急いでタイプミスしたコマンドを修正しました... includeコマンド(SamBのバージョン)の方が優れていることに同意しますが、rsyncにはもう少し複雑で固有ですが**、他の状況でも同様に便利です。
マルセルスティムバーグ

1
Bash 4は同じ機能を採用しています。ああ、あなたはここでrsyncを必要としません、cpはします。一部のシステムでは、多数のファイルがある場合cd ~/Latex && cp -p **/*.pdf ~/Output、「コマンドラインが長すぎます」エラーを回避するのに役立ちます。
ジル

1
includeおよびexcludeフィルターで使用されるrsyncのパターンには、同じことを行う**もあります。*を引用符で囲むことにより、他のシェルから*をエスケープできます。
ダンプリッツ

13

findとの中間リスト(files_to_copy)を使用して問題を解決できます。ホームディレクトリにいることを確認してから:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Bashでテスト済み。


findは最も堅牢なソリューションだと思いますが、finds -execオプションを使用するか、を使用することを選択しますxargs。何かのように:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
スティーブン・D

うん...私も見つける...私はrsyncは想像してもお勧めしたいしなければならないこれを行うことができます。
ガベ。

これは、同様に難しい問題にきちんとしたソリューションです。おそらく私は、その文書クラスであるファイル除外するためにこれを使用することができますstandaloneか持たない.texこれらの画像は、いくつかの文書に含まれるので、同じ名前のファイルを...
シーマス

2
rsyncオプション--files-fromは、stdinからの読み取りを受け入れます。これはうまくいくでしょう find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
フアンカレロ

9

マンページの「INCLUDE / EXCLUDE PATTERN RULES」セクションから判断すると、これを行う方法は

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

これとkbrdの答えの重要な違いは--include="*/"フラグです。これは、rsyncに、名前が何であれ、見つかったディレクトリをコピーするよう指示します。これは、サブディレクトリをコピーするように指示されていない限り、rsyncがサブディレクトリに再帰しないために必要です。

また、引用符は、シェルが現在のディレクトリに関連するファイル名にパターンを展開しようとするのを防ぎ、次のいずれかを実行することに注意してください。

  1. フィルターの成功と混乱(そのようなフラグの真ん中にいる可能性はあまり高くありませんが、誰かがいつ名前のファイルを作成するかは本当にわかりませんが--include=foo.pdf...)

  2. 失敗し、コマンドを実行する代わりにエラーを生成する可能性があります(zshがデフォルトで発見したように)。


したがって、これはPDFとディレクトリ構造のみをコピーしますが、kbrdはファイルをコピーしますが、構造を無視しますか?
シーマス

1
うーん。これは実際にはまだすべてをコピーしようとしているように見えますが、それはフィルターなしでそれが行うincludeことなので、すでにそこにある余分なものを変更しても何も変わりません。あなたが私が意味することを見るなら...
シーマス

7
--exclude="*"後に必要です。そうしないと--include="*.pdf"、すべてが転送されます。
jmanning2k

@ jmanning2k:ああ。知っておきたい!
SamB

4

これはどう:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/

いいえ、man rsyncオプションの後、ソース/宛先の前にフィルターを配置します。私はこれを試しましたが、うまくいきませんでした
Seamus

あなたの方法では、現在のフォルダーで.pdfファイルを検索しますが、再帰的には検索しません。(aオプションはアーカイブ用であり、特にコピーを再帰的にします。
Seamus10年

1
おっと、私の悪い。回答を更新しました。
-kbyrd

+1が非常に近く、マニュアルページで関連資料を見つける方法についての手がかりを与えてくれました。(うまくいけば、私もそれを正しくした。:-)
SamB

3

以下に、findを使用せずに機能するものを示します。既に投稿された回答との違いは、フィルタールールの順序です。rsyncコマンドのフィルタールールは、iptableルールとよく似ています。ファイルが一致する最初のルールが使用されます。マニュアルページから:

転送するファイル/ディレクトリのリストが作成されると、rsyncは転送される各名前を包含/除外パターンのリストに対して順番にチェックし、最初に一致したパターンが処理されます:除外パターンの場合、そのファイルはスキップされました; 包含パターンの場合、そのファイル名はスキップされません。一致するパターンが見つからない場合、ファイル名はスキップされません。

したがって、次のようなコマンドが必要です。

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

「**。pdf」パターンに注意してください。manページによると:

パターンに/(末尾の/をカウントしない)または「**」が含まれる場合、先行するディレクトリを含む完全なパス名と照合されます。パターンに/または "**"が含まれていない場合、ファイル名の最後のコンポーネントとのみ一致します。(アルゴリズムは再帰的に適用されるため、「完全なファイル名」は実際には開始ディレクトリから下のパスの任意の部分になります。

私の小さなテストでは、これはディレクトリツリーで再帰的に機能し、pdfのみを選択します。


どのくらい正確にテストしましたか?ドキュメントの理解と実験的な検証によると、コマンドは*.pdfトップレベルディレクトリにのみコピーする必要があります(ただし、コピーはしないでください~/LaTeX/foo/bar.pdf)。
ジル

@Gilles Crud。あなたが正しいです。私はこれをテストし、機能したと誓ったが、それを再現することはできないようだ。そして今、私が引用したマニュアルページを実際に読んだので、それが機能しないことは理にかなっています。不平を言う。
スティーブンD

1
さて、テストがどこで間違っていたのかがわかりました。私の「小さなテスト」は、自分の.texおよび.pdfファイルがあるディレクトリにありました。次に、そのサブディレクトリに「test」サブディレクトリとtest.pdfおよびtest.texを作成しました。ただし、おそらく私が行ったLaTeXの実験のいくつかの簡単なために、トップレベルのディレクトリにtest.pdfがあることに気づきませんでした。
スティーブンD

私はまだ理解していません**。その例を挙げるといいでしょう。;)
buhtz

2

これは私の好みのソリューションです:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

このfindコマンドは、rsync:-)の包含/除外ルールよりも理解しやすい

pdfファイルのみをコピーする場合は、次のように変更.jpgします。.pdf

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.