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


128

Я намагаюся створити каталог, в якому будуть розміщені всі та лише мої PDF-файли, зібрані з LaTeX. Мені подобається зберігати кожен проект у окремій папці, усі вони розміщені у великій папці під назвою LaTeX. Тому я спробував запустити:

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

який повинен знайти всі pdfs у ~/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/***'це зробимо.
    • Для кожного файлу застосовується перше правило узгодження (і все, що ніколи не збігається, включено).
  • Шаблони:

    • Якщо шаблон не містить а /, він застосовується до каталогу імен файлів sans.
    • Якщо шаблон закінчується /, він стосується лише каталогів.
    • Якщо шаблон починається з /, він застосовується до всього шляху з каталогу, який був переданий як аргумент rsync.
    • *будь-яка підрядка одного компонента каталогу (тобто ніколи не збігається /); **відповідає будь-якій підрядковій трасі.
  • Якщо аргумент джерела закінчується символом a /, його вміст копіюється ( 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 у папку верхнього рівня. Він не буде слідкувати за жодними каталогами, оскільки вони виключені символом "*".


2
Станом на 17.03.2014 це найкраща відповідь, оскільки вона точно вирішує питання оригіналу плакатів . Будь ласка, проголосуйте! Якщо ви додасте --prune-empty-dirs(або ярлик -m), ви навіть шкодуєте собі багато порожніх каталогів у пункті призначення, за винятком, звичайно, ви хочете, щоб вони були нагадуванням або структурним планом.
порг

1
Найкраща відповідь - ключ --include = "* /".
Мартін Конічек

Я хочу включити лише один каталог і виключити решту всього каталогу у /etc/lsyncd/lsyncd.conf.luaфайлі. Маєте якусь ідею?
Дахук Мітеш

15

Якщо ви використовуєте такий зразок *.pdf, оболонка "розширює" цей шаблон, тобто замінює шаблон на всі збіги в поточному каталозі. Команда, яку ви виконуєте (у даному випадку rsync), не знає про те, що ви намагалися використовувати шаблон.

Якщо ви використовуєте zsh , є просте рішення, однак: Цей **шаблон можна використовувати для рекурсивного зіставлення папок. Спробуйте це:

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

Хіба це не скопіювало б усі файли pdfs звідкись у поточному каталозі та все з ~ / LaTeX / до ~ / Output?
СамБ

Я думаю, ви мали на увазі rsync -avn ~/LaTeX/**/*.pdf ~/Output, але рішення з --includeбудь-яким чином більш масштабоване.
Адам Біртек

Вибачте, виправлена ​​команда, яку я поспішно вводив з помилкою ... Я погоджуюся, що команда include (у версії SamB) є кращою, хоча вона є дещо складнішою і специфічною для rsync, а **може стати корисною і в інших ситуаціях.
Марсель Стімберг

1
Bash 4 прийняв ту саму особливість. О, і вам тут не потрібен rsync, cp зробить. У деяких системах, якщо файлів багато, це допомагає cd ~/Latex && cp -p **/*.pdf ~/Outputуникнути помилки «командного рядка занадто довго».
Жиль

1
Зауважте, що шаблони rsync, які використовуються у фільтрах включення та виключення, також мають **, що робить те ж саме. Ви можете втекти * з інших оболонок, поставивши їх у лапки.
Dan Pritts

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

Тестували з Башем.


Я думаю, що пошук є найбільш надійним рішенням, але я б вирішив або використовувати -execваріант знахідки, або використовувати xargs. Щось на кшталт:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Стівен D

Так ... я б запропонував знайти також ... хоча я думаю, що rsync повинен це вміти.
габе.

Це також акуратне рішення більш важкої проблеми: імовірно, я міг би використати це для виключення файлів, клас класів документів standaloneабо яких не має .texфайлу з тим самим іменем, оскільки це будуть зображення, включені в якийсь документ ...
Seamus

2
Опція rsync --files-fromприймає читання з stdin. Це спрацювало б 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's копіюватиме файли, але ігнорувати структуру?
Seamus

1
Хм. Це насправді все ще намагається скопіювати все, я думаю, тому що це робиться без фільтра, тож includeзайві речі, які вже є там, нічого не змінюють. Якщо ви бачите, що я маю на увазі ...
Seamus,

7
Вам потрібно --exclude="*"після --include="*.pdf", або це все перенесе.
jmanning2k

@ jmanning2k: Ага. Добре знати!
SamB

4

Як щодо цього:

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

Ні, man rsyncставить фільтр після параметрів та перед джерелом / дестинаціями. Я спробував це, і нічого не вийшло
Seamus

Ваш спосіб знаходить .pdf файли у поточній папці, але не рекурсивно, як я хочу. ( aопція призначена для архіву. Крім того, це робить копіювання рекурсивним.
Seamus

1
Ой, мій поганий. Я оновив свою відповідь.
kbyrd

+1 за те, що я настільки близький, і дає мені зрозуміти, як знайти відповідний матеріал на сторінці керівництва. (Сподіваюсь, я це навіть правильно зрозумів. :-)
SamB

3

Ось те, що повинно працювати, не використовуючи пошук. Відмінність від уже опублікованих відповідей - це порядок правил фільтра. Правила фільтрації в команді rsync дуже схожі на правила iptable, перше правило, яке відповідає файлу, - це те, що використовується. З сторінки керівництва :

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

Таким чином, вам потрібна така команда:

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

Зверніть увагу на шаблон "**. Pdf". За даними сторінки людини :

якщо шаблон містить / (не рахуючи проміжного /) або "**", він узгоджується з повною назвою шляху, включаючи будь-які провідні каталоги. Якщо шаблон не містить / або "**", він узгоджується лише з кінцевим компонентом імені файлу. (Пам'ятайте, що алгоритм застосовується рекурсивно, тому "повне ім'я файлу" насправді може бути будь-якою частиною шляху від стартового каталогу вниз

У моєму невеликому тесті це працює рекурсивно вниз по дереву каталогів і вибирає лише pdfs.


Як саме ви протестували? Згідно з моїм розумінням документації та моїм експериментальним підтвердженням, ваша команда повинна копіювати лише *.pdfв каталозі верхнього рівня (але не ~/LaTeX/foo/bar.pdf).
Жиль

@Gilles Crud Ти правий. Я поклявся, що перевірив це, і це спрацювало, але, здається, не відтворити це. І тепер, коли я фактично читаю сторінку чоловіка, яку я цитував, має сенс, що це не працює. Бурмотить.
Стівен Д

1
Ну, я зрозумів, де мій тест був невірним. Мій "маленький тест" був у каталозі, у якому є власні файли .tex та .pdf. Потім я створив підкаталог "test" та test.pdf та test.tex у цьому підкаталозі. Однак я не помітив, що в моєму режимі верхнього рівня був test.pdf, ймовірно, через якийсь швидкий експеримент з LaTeX, який я зробив.
Стівен Д

Я досі не розумію **. Було б добре мати приклад. ;)
buhtz

2

Це моє бажане рішення:

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

findКоманда легше зрозуміти , ніж включити / виключити правила rsync:-)

Якщо ви хочете скопіювати лише PDF-файли, просто перейдіть .jpgна.pdf

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