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

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

user1957413
источник
4
Почему вы используете --exclude='*'?
2
поэтому он исключает все, что не является частью включения.
'скрытие файла 1Name.txt из-за шаблона ' это означает: - "должно ли это быть - исключить правило, которое должно быть в команде?" или если вы хотите исключить некоторые файлы, тогда почему " ".
Акшай Патил

Ответы:

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/
sqweek
источник
Пытался запустить его, столкнулся с проблемами с командой cut. Кажется, -tэто действительный переключатель.
редактировать: я имел в виду -t не является допустимым переключателем
извините, должно быть -d. я начал с использования sed, а затем переключился на обрезку, потому что думал, что это было более
Последующие действия: Попытка отредактировать скрипт, чтобы принимать аргументы ($ 1 = path_to_search, $ 2 в качестве шаблона для egrep), так как я сопоставляю имя файла + сочетание расширений. Эта часть работает нормально, я получил ожидаемый список, однако rsync не удается скопировать. Кажется, что он работает только с каталогом символов с одним именем, как в примере (а), я думаю, что команда cut должна быть изменена, чтобы вырезать символы на основе родительского / или исходного dir? В
некотором роде
Ах да, вы совершенно правы. Он должен работать с именем каталога любой длины, но завершится ошибкой, как только вы обратитесь к каталогу за пределами текущего каталога (поскольку в префиксе будет другое количество слешей). Чтобы исправить это, возможно, проще всего использовать sed вместо cut, например: 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, какие шаблоны нужно включить. Второе правило необходимо, чтобы rsync проверил все каталоги на предмет его обхода. Чтобы предотвратить включение пустых папок, они исключаются явно по -mвыбору. Последнее правило фильтра указывает rsync удалить все оставшиеся шаблоны, которые до сих пор не совпадали.

Sparkie
источник
Сладкий. Это тоже сработало. Я получил папку внутри b, которая была исправлена ​​с использованием a / b / в качестве источника и места назначения. Благодарность!
user1957413
Используйте -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("/[^/]*$")).
субботу
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 *
user1957413
источник
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.

фобические
источник