web-dev-qa-db-ja.com

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

私はrsyncを実行して、ファイル名のパターンに基づいてパスに再帰的にいくつかのファイルをコピーしようとしていますinsensitive。これは私が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]*'およびその他の組み合わせですが、まだ機能しません。

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

11
user1957413

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の結果の前に余分な「./」があるため、cutコマンドを変更する必要があることを意味します。

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

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

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

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

7
sparkie

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/

(これらのセレクターで除外する必要はないと思います)

2

上記の@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/
1
Ryan Williams

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

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

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

したがって、findrsyncのみを使用する必要があります。

0
phobic

私が最も経験のある言語なので、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
user1957413