it-swarm-ru.tech

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

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

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

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

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

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


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

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

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

142
Seamus

TL, DR:

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

Rsync копирует источник (и) в место назначения. Если вы передадите *.pdf как источники, Shell расширяет это до списка файлов с .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/
274
Gilles 'SO- stop being evil'
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

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

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

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

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

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

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

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

30
jmanning2k

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

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

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
15
Marcel Stimberg

Вы можете использовать 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.

13
Derek Frye

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

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

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

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

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

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

9
SamB

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

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

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

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

3
guettli

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

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

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

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

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

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

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

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

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

2
Steven D

Чтобы создать каталог, содержащий только заголовки (../include) из исходного каталога:

rsync -avh --Prune-empty-dirs --exclude="build" --include="*/" --include="*.h" --exclude="*" ./* ../include/

Это исключает все пустые каталоги и каталог build

0
SCG82