rsync за допомогою regex для включення лише деяких файлів


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 через шаблон ', це вказує: - "чи потрібно, щоб команда --exclude повинна бути в команді?" або Якщо ви хочете виключити деякі файли, тоді чому " ".
Акшай Патіль

Відповіді:


5

rsync не говорить регулярно. Ви можете зарахувати пошук і греп, хоча це стає трохи таємницею. Щоб знайти цільові файли:

find a/ |
grep -i 'name'

Але всі вони мають префікс "a /" - що має сенс, але все, що ми хочемо в кінцевому підсумку, - це список включень шаблонів, прийнятних для rsync, і оскільки префікс "a /" не працює для rsync I " виймемо його зрізом:

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/". Це тонко, але важливо. Щоб зробити більш послідовними, я збираюся внести одну остаточну зміну і завжди посилаюсь на вихідний каталог як "./a/". Однак це означає, що команда cut повинна змінитися, оскільки на передній частині результатів пошуку знайдеться додатковий "./":

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

Спробував запустити його, зіткнувся з проблемами з командою cut. Здається, -tщо це дійсний перемикач.

редагувати: я мав на увазі - це

вибачте, має бути -d. я почав використовувати sed, а потім змінив на скорочення, тому що думав, що це зрозуміліше, але забув редагувати свої команди: S

Подальше: Спробували відредагувати сценарій, щоб взяти аргументи ($ 1 = path_to_search, $ 2 як зразок для egrep), оскільки я збігаю назву файлу + суміш розширень. Ці частини добре працюють, я отримав очікуваний список, проте rsync не може скопіювати. Здається, працює лише з каталогом символів єдиного імені, як у прикладі (а) я здогадуюсь, що команда cut має бути змінена, щоб вирізати символи на основі батьків / або джерела dir? Якимось чином програв, як це зробити:
user1957413

Ага так, ви абсолютно праві. Він повинен працювати над назвою каталогу будь-якої довжини, але вийде з ладу, як тільки ви звернетеся до каталогу за межами поточного каталогу (тому що в частині префікса буде різна кількість косих рядків). Щоб виправити це, напевно, найпростіше використовувати sed замість вирізання, як-от: sed "s#^$1/*##" buuuut, який буде ламатись на шляхах, що містять #. Щоб виправити, що ми повинні навести ім'я вхідної каталоги: prefix=$(echo "$1" | sed 's#/#\\/#g')а потім sed "s/^$prefix\\/*//" суботити баш-цитування - це трохи кошмар;)
sqweek

7

Я б запропонував використати варіант фільтра rsync. Для вашого прикладу просто введіть:

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

перше правило фільтра повідомляє rsync, які шаблони включати. Друге правило потрібне, щоб сказати rsync перевірити всі каталоги на його обході. Щоб запобігти включенню порожніх грядок, вони виключаються явно за -mопцією. Останнє правило фільтра вказує rsync розпоряджатись усіма залишилися шаблонами, які досі не відповідали.


Солодке. Це також спрацювало. Я отримував папку всередині b, яку виправляли, використовуючи a / b / як джерело та призначення. Спасибі!
користувач1957413

Використовуйте -f '+ * [Nn] [Aa] [Mm] [E] **' (дві зірки в кінці), щоб включити вміст усіх каталогів із конкретною назвою.
фобічний

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

[EDIT] Це працює лише локально. Для віддалених шляхів спочатку слід створити структуру каталогів.

Більш проста, ніж прийнята відповідь; Використовуйте --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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.