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]*' и другие комбинации, но это все еще не идет.

Любые идеи о том, как использовать регулярные выражения для включения некоторых файлов?

6 ответов6

6

Я бы предложил использовать параметр фильтра rsync. Для вашего примера просто введите:

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

первое правило фильтра сообщает rsync, какие шаблоны нужно включить. Второе правило необходимо, чтобы rsync проверил все каталоги на предмет его обхода. Чтобы предотвратить включение пустых папок, они явно исключаются опцией -m . Последнее правило фильтра указывает rsync удалить все оставшиеся шаблоны, которые до сих пор не совпадали.

5

Rsync не говорит регулярных выражений. Вы можете подключить find и grep, хотя это немного загадочно. Чтобы найти целевые файлы:

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

Если вы используете 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/

(Я не вижу необходимости исключения из этих селекторов)

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 .

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 *

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .