Фильтр Rsync: копирование только одного шаблона

128

Я пытаюсь создать каталог, в котором будут храниться все и только мои PDF-файлы, скомпилированные из LaTeX. Мне нравится хранить каждый проект в отдельной папке, все в большой папке LaTeX. Итак, я попытался запустить:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

который должен найти все PDF-файлы в ~/LaTeX/и передать их в выходную папку. Это не работает Это говорит мне, что не найдено соответствий для " *.pdf". Если я пропущу этот фильтр, команда перечислит все файлы во всех папках проекта в LaTeX. Так что это проблема с фильтром * .pdf. Я попытался заменить ~/полный путь к моему домашнему каталогу, но это не дало эффекта.

Я использую Zsh. Я пытался сделать то же самое в bash и даже с фильтром, который перечислял каждый файл в каждом подкаталоге ... Что здесь происходит?

Почему rsync не понимает мой фильтр только для PDF?


ХОРОШО. Итак, обновление: нет, я пытаюсь

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

И это дает мне весь список файлов. Я думаю, потому что все соответствует первому шаблону ...

Симус
источник
э-э, вы, кажется, правы ... Я думаю, что мой ответ (используя **шаблон zsh ) должен работать.
Марсель Стимберг

Ответы:

248

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync копирует источник (и) в место назначения. Если вы передадите в *.pdfкачестве источников, оболочка расширит это до списка файлов с .pdfрасширением в текущем каталоге. Никакого рекурсивного обхода не происходит, потому что вы не передали ни один каталог в качестве источника.

Так что вам нужно запустить rsync -a ~/LaTeX/ ~/Output/, но с фильтром, чтобы rsync копировал .pdfтолько файлы. Правила фильтра Rsync могут показаться пугающими, когда вы читаете руководство, но вы можете создать множество примеров с помощью нескольких простых правил.

  • Включения и исключения:

    • Исключение файлов по имени или по местоположению легко: --exclude=*~, --exclude=/some/relative/location( по отношению к исходному аргументу, например , это исключает ~/LaTeX/some/relative/location).
    • Если вы хотите сопоставить только несколько файлов или местоположений, включите их, включите все ведущие к ним каталоги (например, с помощью --include=*/), а затем исключите остальные с помощью --exclude='*'. Это потому что:
    • Если вы исключаете каталог, это исключает все, что находится под ним. Исключенные файлы не будут рассматриваться вообще.
    • Если вы включаете каталог, он автоматически не включает его содержимое. В последних версиях --include='directory/***'сделаю это.
    • Для каждого файла применяется первое правило соответствия (и все, что никогда не совпадало, включено).
  • Шаблоны:

    • Если шаблон не содержит /, он применяется к каталогу без имени файла.
    • Если шаблон заканчивается на /, он применяется только к каталогам.
    • Если шаблон начинается с /, он применяется ко всему пути из каталога, который был передан в качестве аргумента rsync.
    • *любая подстрока одного компонента каталога (т.е. никогда не совпадает /); **соответствует любой подстроке пути.
  • Если исходный аргумент заканчивается на /, его содержимое копируется ( rsync -r a/ bсоздается b/fooдля каждого a/foo). В противном случае сам каталог копируется ( rsync -r a bсоздается b/a).


Таким образом, здесь мы должны включить *.pdf, включить каталоги, содержащие их, и исключить все остальное.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Обратите внимание, что при этом копируются все каталоги, даже те, которые не содержат соответствующего файла или подкаталога, содержащего один. Этого можно избежать с помощью этой --prune-empty-dirsопции (это не универсальное решение, поскольку вы не сможете скопировать каталог, даже если сопоставите его явно, но это редкое требование).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
жилль
источник
В отличие от моего решения (с использованием **шаблона zsh ), это воссоздает структуру каталогов в целевой директории. Я не уверен, хочет ли это то, что хочет ОП ...
Марсель Стимберг
Я хочу включить только один каталог и исключить остаток всех каталогов в /etc/lsyncd/lsyncd.conf.luaфайле. Есть идеи?
Дхадук Митеш
@DhadukMitesh Я не знаком с lsyncd. Вы должны задать это как новый вопрос.
Жиль
25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

По умолчанию все включено, поэтому вы должны явно исключить все после включения файлов, которые вы хотите передать. Удалите --dry-run для фактической передачи файлов.

Если вы начинаете с:

--exclude '*' --include '*.pdf'

Тогда жадное совпадение сразу все исключит.

Если вы пытаетесь:

--include '*.pdf' --exclude '*' 

Тогда только файлы PDF в папке верхнего уровня будут переданы. Он не будет следовать ни за какими каталогами, так как они исключаются знаком *.

jmanning2k
источник
2
По состоянию на 2014-03-17 это лучший ответ, как он решает оригинальные плакаты вопрос точно . Пожалуйста, проголосуйте! Если вы добавите --prune-empty-dirs(или ярлык -m), вы даже сэкономите много пустых каталогов в месте назначения, кроме тех случаев, когда вы хотите, чтобы они были напоминанием или структурным планом.
porg
1
Лучший ответ, --include = "* /" является ключевым.
Мартин Коничек,
Я хочу включить только один каталог и исключить остаток всех каталогов в /etc/lsyncd/lsyncd.conf.luaфайле. Есть идеи?
Дхадук Митеш
15

Если вы используете шаблон как *.pdf, оболочка «расширяет» этот шаблон, то есть заменяет шаблон на все совпадения в текущем каталоге. Команда, которую вы запускаете (в данном случае rsync), не знает о том, что вы пытались использовать шаблон.

Когда вы используете zsh , существует простое решение: **шаблон можно использовать для рекурсивного сопоставления папок. Попробуй это:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
Марсель Стимберг
источник
Разве это не скопирует все PDF-файлы из текущего каталога и все из ~ / LaTeX / в ~ / Output?
SamB
Я полагаю, вы имели в виду rsync -avn ~/LaTeX/**/*.pdf ~/Output, но в --includeлюбом случае решение с более масштабируемым.
Адам Быртек
Извините, исправил команду, которую я набрал неправильно в спешке ... Я согласен, что команда include (в версии SamB) лучше, хотя она немного сложнее и специфична для rsync, хотя **может пригодиться и в других ситуациях.
Марсель Стимберг
1
Bash 4 принял ту же функцию. О, и вам не нужен rsync, cp подойдет. В некоторых системах, если файлов много, это помогает cd ~/Latex && cp -p **/*.pdf ~/Outputизбежать ошибки «слишком длинная командная строка».
Жиль
1
Обратите внимание, что шаблоны rsync, используемые в фильтрах include и exclude, также имеют **, что делает то же самое. Вы можете убежать * от других оболочек, поставив их в кавычки.
Дэн Притц
13

Вы можете использовать findи промежуточный список файлов ( files_to_copy) для решения вашей проблемы. Убедитесь, что вы находитесь в своем домашнем каталоге, а затем:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Протестировано с Bash.

Дерек Фрай
источник
Я думаю, что find - это самое надежное решение, но я бы выбрал -execвариант использования find или использование xargs. Что-то вроде:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Стивен Д.
Да ... я бы тоже посоветовал найти ... хотя я полагаю, что rsync должен это сделать.
таращиться
Это также изящное решение более сложной проблемы: возможно, я мог бы использовать это для исключения файлов с классом документа, standaloneкоторые не имеют .texфайла с тем же именем, так как это будут изображения, включенные в некоторый документ ...
Симус
2
Опция rsync --files-fromпринимает чтение из стандартного ввода. Это будет работать find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Хуан Калеро
9

Судя по разделу «ВКЛЮЧИТЬ / ИСКЛЮЧИТЬ ПРАВИЛА ШАБЛОНА» на странице руководства, способ сделать это

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

Критическое различие между этим и ответом kbrd заключается в --include="*/"флаге, который говорит rsync идти вперед и копировать любые найденные каталоги, как бы они ни назывались. Это необходимо, потому что rsync не будет возвращаться в подкаталог, если ему не было поручено скопировать этот подкаталог.

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

  1. Преуспеть и испортить ваш фильтр (не слишком вероятно в середине флага, подобного этому, хотя вы действительно никогда не знаете, когда кто-то создаст файл с именем --include=foo.pdf...)

  2. Сбой и потенциальная ошибка вместо выполнения команды (как вы обнаружили, zsh делает по умолчанию).

Самба
источник
Таким образом, это будет копировать только PDF-файлы и структуру каталогов, в то время как kbrd будет копировать файлы, но игнорировать структуру?
Симус
1
Хм. Кажется, что на самом деле это все еще пытается скопировать все, я полагаю, потому что это то, что он делает без фильтра, так что includeдобавление дополнительных вещей уже ничего не меняет. Если вы видите , что я имею в виду ...
Симус
7
Вам нужно --exclude="*"после --include="*.pdf", или это все перенесет.
jmanning2k
@ jmanning2k: Ах. Хорошо знать!
SamB
4

Как насчет этого:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
kbyrd
источник
Нет, man rsyncустанавливает фильтр после опций и перед источником / назначением. Я попробовал это, и это не сработало
Симус
Ваш путь находит файлы .pdf в текущей папке, но не рекурсивно, как я хочу. ( aопция для архива и, кроме всего прочего, делает рекурсивное копирование.
Симус
1
Упс, мой плохой. Я обновил свой ответ.
2010 года
+1 за то, что так близко, и дал мне подсказку о том, как найти соответствующий материал на странице руководства. (Надеюсь, я даже понял это правильно. :-)
SamB
3

Вот то, что должно работать без использования find. Отличие от уже опубликованных ответов заключается в порядке правил фильтрации. Правила фильтрации в команде rsync работают во многом подобно правилам iptable, первое правило, которому соответствует файл, - это то, которое используется. Со страницы руководства :

Поскольку список файлов / каталогов для передачи создается, rsync проверяет каждое передаваемое имя по списку шаблонов включения / исключения по очереди, и действует первый соответствующий шаблон: если это шаблон исключения, то этот файл пропускаются; если это шаблон включения, то это имя файла не пропускается; если соответствующий шаблон не найден, то имя файла не пропускается.

Таким образом, вам нужна команда следующим образом:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Обратите внимание на шаблон «**. Pdf». Согласно справочной странице :

если шаблон содержит / (не считая завершающего /) или "**", то он сопоставляется с полным путем, включая любые ведущие каталоги. Если шаблон не содержит / или «**», то он сопоставляется только с последним компонентом имени файла. (Помните, что алгоритм применяется рекурсивно, поэтому «полное имя файла» может фактически быть любой частью пути от начального каталога до

В моем небольшом тесте это работает рекурсивно вниз по дереву каталогов и выбирает только PDF-файлы.

Стивен Д
источник
Как именно вы тестировали? Согласно моему пониманию документации и моей экспериментальной проверке, ваша команда должна копироваться только *.pdfв каталог верхнего уровня (но не в него ~/LaTeX/foo/bar.pdf).
Жиль
@ Жиль Круд. Ты прав. Я поклялся, что проверил это, и это сработало, но я не могу воссоздать это. И теперь, когда я прочитал справочную страницу, которую я цитировал, стало понятно, что она не работает. Ворчать.
Стивен Д.
1
Ну, я выяснил, где мой тест был неверным. Мой "маленький тест" был в каталоге, в котором есть мои .tex и .pdf файлы. Затем я создал подкаталог «test» и test.pdf и test.tex в этом подкаталоге. Однако я не заметил, что в моем каталоге верхнего уровня был файл test.pdf, вероятно, из-за одного быстрого эксперимента LaTeX, который я провел.
Стивен Д.
Я до сих пор не понимаю **. Было бы неплохо иметь пример этого. ;)
Бухц
2

Это мое предпочтительное решение:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

findКоманда легче понять , чем включить / исключить правила rsync:-)

Если вы хотите скопировать только PDF-файлы, просто измените .jpgна.pdf

guettli
источник