rsync sử dụng regex để chỉ bao gồm một số tệp


11

Tôi đang cố gắng chạy rsync để sao chép một số tệp đệ quy xuống một đường dẫn dựa trên mẫu tên tệp của chúng, không phân biệt chữ hoa chữ thường . Đây là những gì tôi đã làm để chạy rsync:

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

Không có gì được sao chép, đầu ra gỡ lỗi hiển thị:

[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 *

Tôi đã thử sử dụng: --include='*[Nn][Aa][Mm][E]*'và các kết hợp khác nhưng nó vẫn không hoạt động.

Bất kỳ ý tưởng về cách sử dụng regex để bao gồm một số tệp?


4
Tại sao bạn sử dụng --exclude='*'?

2
vì vậy nó loại trừ mọi thứ không phải là một phần của bao gồm.

'ẩn tệp 1Name.txt vì mẫu ', điều này cho biết: - "quy tắc - ngoại lệ đó có cần phải có trong lệnh không?" hoặc Nếu bạn muốn loại trừ một số tệp thì tại sao lại là " ".
Akshay Patil

Câu trả lời:


5

rsync không nói regex. Bạn có thể tranh thủ tìm và grep, mặc dù nó có một chút phức tạp. Để tìm các tệp mục tiêu:

find a/ |
grep -i 'name'

Nhưng tất cả chúng đều có tiền tố là "a /" - điều này có ý nghĩa, nhưng điều chúng tôi muốn kết thúc là một danh sách các mẫu bao gồm chấp nhận được với rsync và vì tiền tố "a /" không hoạt động cho rsync I ' sẽ loại bỏ nó bằng cắt:

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

Vẫn còn một vấn đề - chúng tôi vẫn sẽ bỏ lỡ các tệp trong thư mục con, vì rsync không tìm kiếm các thư mục trong danh sách loại trừ. Tôi sẽ sử dụng awk để thêm các thư mục con của bất kỳ tệp phù hợp nào vào danh sách các mẫu bao gồm:

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

Tất cả những gì còn lại là gửi danh sách tới rsync - chúng ta có thể sử dụng đối số --include-from = - để cung cấp danh sách các mẫu cho rsync trên đầu vào tiêu chuẩn. Vì vậy, hoàn toàn:

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

Lưu ý rằng thư mục nguồn 'a' được tham chiếu qua hai đường dẫn khác nhau - "a /" và "./a/". Điều này là tinh tế nhưng quan trọng. Để làm cho mọi thứ phù hợp hơn, tôi sẽ thực hiện một thay đổi cuối cùng và luôn xem thư mục nguồn là "./a/". Tuy nhiên, điều này có nghĩa là lệnh cắt phải thay đổi vì sẽ có thêm "./" ở phía trước kết quả từ find:

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

Đã thử chạy nó, chạy vào các vấn đề với lệnh cắt. Có vẻ đó -tlà một chuyển đổi hợp lệ.

chỉnh sửa: ý tôi là -t không phải là một công tắc hợp lệ

xin lỗi, nên -d. Tôi bắt đầu sử dụng sed và sau đó thay đổi để cắt vì tôi nghĩ nó rõ ràng hơn, nhưng quên chỉnh sửa các lệnh của tôi: S

Theo dõi: Đã thử chỉnh sửa tập lệnh để lấy đối số ($ 1 = path_to_search, $ 2 làm mẫu cho egrep) vì tôi khớp tên tệp + kết hợp các tiện ích mở rộng. Các bộ phận đó hoạt động tốt, tôi đã nhận được danh sách dự kiến, tuy nhiên rsync không sao chép. Nó dường như chỉ hoạt động với thư mục ký tự tên duy nhất như trong ví dụ (a) tôi đoán là lệnh cắt phải được sửa đổi để cắt các ký tự dựa trên thư mục gốc / hoặc nguồn? Mất một cách để làm điều đó:
user1957413

À đúng rồi, bạn khá đúng. Nó sẽ hoạt động trên một tên thư mục có độ dài bất kỳ, nhưng sẽ thất bại ngay khi bạn tham khảo một thư mục bên ngoài thư mục hiện tại (vì sẽ có một số dấu gạch chéo khác nhau trong phần tiền tố). Để khắc phục điều đó, có lẽ dễ sử dụng sed nhất thay vì cắt, như: sed "s#^$1/*##" buuuut sẽ phá vỡ trên các đường dẫn có chứa #. Để khắc phục điều đó, chúng tôi phải trích dẫn tên thư mục đến: prefix=$(echo "$1" | sed 's#/#\\/#g')và sau đó sed "s/^$prefix\\/*//" Các phần phụ của trích dẫn bash là một cơn ác mộng;)
sqweek

7

Tôi sẽ đề nghị sử dụng tùy chọn bộ lọc của rsync. Ví dụ của bạn chỉ cần gõ:

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

quy tắc bộ lọc đầu tiên cho rsync biết những mẫu cần bao gồm. Quy tắc thứ hai là cần thiết để yêu cầu rsync kiểm tra tất cả các thư mục trên giao dịch của nó. Để ngăn chặn các thư mục trống từ việc đưa vào, chúng được loại trừ rõ ràng bằng -mtùy chọn. Quy tắc bộ lọc cuối cùng yêu cầu rsync loại bỏ tất cả các mẫu còn lại vẫn chưa khớp.


Ngọt. Điều này làm việc là tốt. Tôi đã nhận được thư mục a bên trong b, đã được sửa bằng cách sử dụng a / b / làm nguồn và đích. Cảm ơn!
1957413

Sử dụng -f '+ * [Nn] [Aa] [Mm] [E] **' (hai ngôi sao ở cuối) để bao gồm nội dung của tất cả các thư mục có tên cụ thể.
phobic

2

Nếu bạn sử dụng ZSH thì bạn có thể sử dụng cờ (#i) để tắt độ nhạy trường hợp. Thí dụ:

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

ZSH cũng hỗ trợ các loại trừ, được chỉ định giống như đường dẫn thông thường nhưng chúng có chữ cái đầu ~

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

Bạn có thể loại trừ chuỗi:

$ ls *~*c~*b
aa

Cuối cùng, bạn có thể chỉ định loại tệp bạn muốn trả về (thư mục, tệp, v.v.). Điều này được thực hiện với (/) cho thư mục và (.) Cho tệp.

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

Dựa trên tất cả điều này, tôi sẽ thực hiện lệnh đó như:

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

(Tôi không thấy cần phải loại trừ với các bộ chọn này)


1

Câu trả lời của @ sqweek ở trên là tuyệt vời, mặc dù tôi nghi ngờ anh ta có một lỗi trong awktập lệnh của mình khi tạo thư mục gốc, vì nó cho tôi ví dụ:

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

Tôi đã có thể sửa nó bằng cách sử dụng gensubthay thế:

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

Vì vậy, giải pháp đầy đủ của anh ấy, với một awkchút thay đổi, sẽ là:

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/

Cảm ơn. Chỉnh sửa câu trả lời của tôi với bản sửa lỗi tương đương là neo biểu thức chính quy vào cuối dòng ( sub("/[^/]*$")).
sqweek

0

Đã thử với tập lệnh C # vì đây là ngôn ngữ tôi có nhiều kinh nghiệm nhất. Tôi có thể tạo danh sách các tệp mà tôi muốn đưa vào, nhưng ai đó rsync vẫn bảo tôi đi bộ. Nó tạo các thư mục, nhưng nó bỏ qua các tập tin. Đây là những gì tôi đã nhận được ..

Đầu tiên nội dung của thư mục:

~/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

Sau đó, đầu ra của tập lệnh C #:

~/mono$ mono test.exe

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

Và đầu ra gỡ lỗi:

~/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

[EDIT] Điều này chỉ hoạt động tại địa phương. Đối với các đường dẫn từ xa, cấu trúc thư mục phải được tạo trước.

Đơn giản hơn câu trả lời được chấp nhận; Sử dụng --file-from, bao gồm các thư mục mẹ tự động và in đường dẫn tệp với% P

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

Vì vậy, bạn chỉ phải sử dụng findrsync.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.