正規表現を使用して一部のファイルのみを含めるrsync


11

rsyncを実行して、ファイル名のパターンに基づいて、大文字と小文字を区別しないパスで再帰的にいくつかのファイルをコピーしようとしています。これは、rsyncを実行するために行ったことです。

$ rsync -avvz --include ='*/' --include='.*[Nn][Aa][Mm][E].*' --exclude='*' ./a/ ./b/

何もコピーされません。デバッグ出力には以下が表示されます。

[sender] hiding file 1Name.txt because of pattern *
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] hiding directory test1 because of pattern *
[sender] hiding file NaMe.txt because of pattern *

私は使用してみました: --include='*[Nn][Aa][Mm][E]*'および他の組み合わせが、それはまだ行きません。

正規表現を使用していくつかのファイルを含める方法に関するアイデアはありますか?


4
なぜ使用してい--exclude='*'ますか?

2
そのため、インクルードの一部ではないものはすべて除外されます。

「パターンためにファイル1Name.txtを非表示にする」これは、次のことを示しています。またはいくつかのファイルを除外したい場合は、なぜ「」。
Akshayパティル

回答:


5

rsyncは正規表現を話しません。findとgrepに参加できますが、少し難解です。ターゲットファイルを見つけるには:

find a/ |
grep -i 'name'

しかし、それらはすべて「a /」の接頭辞が付いています-これは理にかなっていますが、最終的にはrsyncで受け入れ可能なインクルードパターンのリストであり、「a /」接頭辞はrsyncでは機能しませんカットで削除します:

find . |
grep -i 'name' |
cut -d / -f 2-

まだ問題があります-rsyncは除外リストのディレクトリを検索しないため、サブディレクトリ内のファイルを見逃します。awkを使用して、一致するファイルのサブディレクトリをインクルードパターンのリストに追加します。

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}'

残っているのは、リストをrsyncに送信することだけです。引数--include-from =-を使用して、標準入力でrsyncにパターンのリストを提供できます。したがって、完全に:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

ソースディレクトリ「a」は、「a /」と「./a/」の2つの異なるパスを介して参照されることに注意してください。これは微妙ですが重要です。物事の一貫性を保つために、最後の変更を1つ行い、ソースディレクトリを常に「./a/」として参照します。ただし、これは、findの結果の前に余分な「./」があるため、カットコマンドを変更する必要があることを意味します。

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

実行しようとしましたが、cutコマンドに問題が発生しました。それ-tは有効なスイッチのようです。

編集:-tが有効なスイッチではないことを意味

すみません、-dにしてください。私はsedを使い始めてから、より明確だと思ったのでcutに変更しましたが、コマンドを編集するのを忘れました:S

フォローアップ:スクリプトを編集して引数($ 1 = path_to_search、egrepのパターンとして$ 2)を編集しようとしました。ファイル名+拡張子の組み合わせに一致しています。その部分は正常に機能し、期待されるリストを取得しましたが、rsyncはコピーに失敗します。例のように単一名の文字ディレクトリでのみ動作するようです(a)私の推測では、親/またはソースディレクトリに基づいて文字をカットするためにカットコマンドを変更する必要がありますか?ちょっとそれを行う方法を失った:
user1957413

ええ、あなたはまったく正しいです。任意の長さのディレクトリ名で動作するはずですが、現在のディレクトリ以外のディレクトリを参照するとすぐに失敗します(プレフィックス部分に異なる数のスラッシュがあるため)。これを修正するには、おそらく、cutの代わりにsedを使用するのが最も簡単です。sed "s#^$1/*##" たとえば、#を含むパスで中断するbuuuutです。これを修正するには、着信ディレクトリ名を引用する必要があります:prefix=$(echo "$1" | sed 's#/#\\/#g')そしてsed "s/^$prefix\\/*//" 、bash引用のサブレットは少し悪夢です;)
sqweek

7

rsyncのフィルターオプションを使用することをお勧めします。あなたの例では、単に入力してください:

rsync -vam -f'+ *[Nn][Aa][Mm][E]*' -f'+ */' -f'- *' a b

最初のフィルタールールは、含めるパターンをrsyncに指示します。2番目のルールは、rsyncにトラバーサルのすべてのディレクトリを検査するように指示するために必要です。空のディレクトリが含まれないようにするために、明示的に除外されます-mオプションでます。最後のフィルタールールは、これまでに一致しなかった残りのパターンをすべて破棄するようにrsyncに指示します。


甘い。これもうまくいきました。フォルダーaをb内に取得していましたが、a / b /をソースおよび宛先として使用することで修正されました。ありがとう!
user1957413

-f '+ * [Nn] [Aa] [Mm] [E] **'(最後に2つ星)を使用して、特定の名前を持つすべてのディレクトリの内容を含めます。
恐怖症

2

ZSHを使用する場合、(#i)フラグを使用して大文字と小文字の区別をオフにすることができます。例:

$ touch NAME
$ ls (#i)*name*
NAME

ZSHは除外もサポートします。除外は通常のパスと同様に指定されますが、最初の〜

$ touch aa ab ac
$ ls *~*c
aa ab

除外を連鎖できます:

$ ls *~*c~*b
aa

最後に、返されるファイルの種類(ディレクトリ、ファイルなど)を指定できます。これは、ディレクトリ用の(/)とファイル用の(。)で行われます。

$ touch file
$ mkdir dir
$ ls *(.)
file

このすべてに基づいて、次のようにコマンドを実行します。

rsync -avvz *(/) (#i)*name* ./a/ ./b/

(これらのセレクターで除外する必要はありません)


1

上記の@sqweekの答えは素晴らしいですが、awk親ディレクトリを生成するためのスクリプトにバグがあると思われます。

$ echo a/b/c/d | awk -F/ '{print; while(/\//) {sub("/[^/]*", ""); print}}'
a/b/c/d
a/c/d
a/d
a

gensub代わりに以下を使用して修正できました。

$ echo a/b/c/d | awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}'
a/b/c/d
a/b/c
a/b
a

それで、awk少し変更された彼の完全なソリューションは次のようになります。

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

ありがとう。正規表現を行末に固定するのと同等の修正(sub("/[^/]*$"))で私の回答を編集しました。
sqweek

0

私が最も経験のある言語なので、C#スクリプトを試してみました。私が含めたいファイルのリストを作成することはできますが、誰かrsyncがまだハイキングをするように言っています。フォルダを作成しますが、ファイルは無視します。ここに私が得たものがあります..

最初にディレクトリのコンテンツ:

~/mono$ ls -l
total 24
drwxr-xr-x 5 me me 4096 Jan 15 00:36 a
drwxr-xr-x 2 me me 4096 Jan 15 00:36 b
drwxr-xr-x 3 me me 4096 Jan 14 00:31 bin
-rw-r--r-- 1 me me 3566 Jan 15 00:31 test.cs
-rwxr-xr-x 1 me me 4096 Jan 15 00:31 test.exe
-rwxr--r-- 1 me me  114 Jan 14 22:40 test.sh

次に、C#スクリプトの出力:

~/mono$ mono test.exe

/a/myfile/myfileseries.pdf
/a/myfile2/testfile.pdf

デバッグ出力:

~/mono$ mono test.exe | rsync -avvvz --include='*/' --include-from=- --exclude='*' ./a/ ./b/
[client] add_rule(+ */)
[client] parse_filter_file(-,20,3)
[client] add_rule(+ /a/myfile/myfileseries.pdf)
[client] add_rule(+ /a/myfile2/testfile.pdf)
[client] add_rule(- *)
sending incremental file list
[sender] make_file(.,*,0)
[sender] hiding file 1Name.txt because of pattern *
[sender] showing directory myfile2 because of pattern */
[sender] make_file(myfile2,*,2)
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] showing directory test1 because of pattern */
[sender] make_file(test1,*,2)
[sender] hiding file NaMe.txt because of pattern *
[sender] showing directory myfile because of pattern */
[sender] make_file(myfile,*,2)
send_file_list done
send_files starting
[sender] hiding file myfile/myfileseries.pdf because of pattern *
[sender] hiding file myfile2/testfile.pdf because of pattern *
[sender] hiding file test1/test.txt because of pattern *

0

[編集]これはローカルでのみ機能します。リモートパスの場合、最初にディレクトリ構造を作成する必要があります。

受け入れられている答えよりも簡単です。--file-fromを使用します。これには、親ディレクトリが自動的に含まれ、%Pでファイルパスが出力されます。

find /tmp/source -wholename '*[Nn][Aa][Mm][E]*' -printf '%P\n' | rsync -vzrm --exclude='*/' --files-from=- /tmp/source/ /tmp/target/

ですからfind、とを使用するだけrsyncです。

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