rsync копирует только определенные типы файлов с помощью опции включения

110

Я использую следующий сценарий bash для копирования только файлов определенного расширения (в данном случае * .sh), однако он по-прежнему копирует все файлы. в чем дело?

от = $ 1
to = $ 2

rsync -zarv --include = "*. sh" $ от $ до
user881480
источник
4
Хотя это, строго говоря, не связано, я бы предложил процитировать $ from / $ to. Невыполнение этого может привести к неожиданным результатам, если позиционные аргументы 1/2 содержат пробелы.
Kjetil Joergensen
Вы поняли, почему ваша команда просто не работает?
Чарли Паркер
@CharlieParker: Вы должны использовать rsync, это вполне может быть достигнуто с помощью внутренних компонентов оболочки?
Inian
Чего также не хватает в этом вопросе и ответах на него, так это о том, как создать команду, если у меня есть рекурсивные каталоги, в которые я хочу отправить только один тип файла. Похоже, это работает только с целевым каталогом ...
Чарли Паркер

Ответы:

200

Я думаю, что --includeиспользуется для включения подмножества файлов, которые в противном случае исключаются --exclude, а не для включения только этих файлов. Другими словами: вы должны думать о включении значения , а не об исключении .

Вместо этого попробуйте:

rsync -zarv  --include "*/" --exclude="*" --include="*.sh" "$from" "$to"

Для версии rsync 3.0.6 или выше порядок необходимо изменить следующим образом (см. Комментарии):

rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"

Добавление -mфлага позволит избежать создания пустых структур каталогов в месте назначения. Проверено в версии 3.1.2.

Поэтому, если нам нужны только файлы * .sh, мы должны исключить все файлы --exclude="*", включить все каталоги --include="*/"и включить все файлы * .sh --include="*.sh".

Вы можете найти несколько хороших примеров в разделе « Правила включения / исключения шаблонов» на странице руководства.

Чепнер
источник
10
Хотя он предоставит вам все подкаталоги, если в подкаталогах, которые вы хотите использовать rsync, есть какие-либо файлы .sh, скорее всего, вы тоже захотите использовать --include = "* /".
Kjetil Joergensen
50
Я пробовал это на rsync версии 3.0.7, которую я давно получил от macports, и это не сработало с таким порядком включения / исключения. Это то , что я закончил с , что работал для меня (адаптировано для OP): rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
Bijou Trouvaille
3
Я пробовал использовать rsync 3.0.9, но ничего не вышло. Бижу прав, упорядочение не является правильным (первым --include=\*.shтогда --exclude=\*)
TrueY
3
Обратите внимание, что вы всегда можете нажать кнопку «Изменить» и предложить
исправление
2
Он не работает с вашим порядком включения / исключения, но он работает с порядком, предложенным Бижу Трувай
Джон Смит Необязательно
57

Ответ @chepner скопирует все подкаталоги независимо от того, содержит ли он файл или нет. Если вам нужно исключить подкаталоги, которые не содержат файл, но при этом сохраняют структуру каталогов, используйте

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
Блуждающий разум
источник
1
Для меня это было требованием: «Если вам нужно исключить подкаталоги, которые не содержат файл, и при этом сохранить структуру каталогов» +1
Юусо Охтонен
1
Я не понимаю, как вы узнали, в каком порядке были включения?
Чарли Паркер
1
Как создать команду, если у меня есть рекурсивные каталоги, в которые я хочу отправить только один тип файла. Кажется, это только для целевого каталога.
Чарли Паркер
15

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

rsync -auzv --include './' --include '*.ext' --exclude '*' /source/dir/ /destination/dir/

Обратите внимание на точку в первом --include. --no-rне работает в этой конструкции.

РЕДАКТИРОВАТЬ:

Спасибо gbyte.co за ценный комментарий!

Серж Руссак
источник
1
как вы узнали, в каком порядке должны быть флаги и что они должны были включать?
Чарли Паркер
1
@CharlieParker, потому что rsync использует параметры includeи excludeв том порядке, в котором они были указаны. В дополнение к этому он останавливается на первом подходящем. Итак, если мы укажем --exclude '*'на первом месте в этом примере, rsync ничего не сделает. См. Этого человека для получения дополнительных объяснений.
Serge Roussak
вы можете мне объяснить, что делает каждый флаг? Первый флаг -- include './' говорит включить все в путь к исходному каталогу? Затем следующий `--include '.ext' 'включает конкретный файл в указанный исходный путь, .extа затем исключение говорит, что больше ничего не отправлять --exclude '*'? Это правильно?
Чарли Паркер
1
Как создать команду, если у меня есть рекурсивные каталоги, в которые я хочу отправить только один тип файла. Кажется, это только для целевого каталога.
Чарли Паркер,
1
Спасибо за это! Потребности в --include '*.ext'и не--include '.ext'
Гбайта
13

Вот важная часть справочной страницы:

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

Подвести итоги:

  • Отсутствие совпадения с шаблоном означает, что файл будет скопирован!
  • Алгоритм завершает работу при совпадении любого шаблона

Кроме того, что-то, заканчивающееся косой чертой, соответствует каталогам (например find -type d,).

Давайте разберем этот ответ сверху.

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. Не пропускайте каталоги
  2. Не пропускайте .shфайлы
  3. Пропустить все
  4. (Неявно ничего не пропускайте, но приведенное выше правило предотвращает выполнение правила по умолчанию.)

Наконец, --prune-empty-directoriesпервое правило не допускает создания пустых каталогов повсюду.

Джим Ханзикер
источник
Большое спасибо за объяснение того, что происходит. Теперь гораздо больше шансов, что я не забуду команду.
MohamedEzz
3
«Алгоритм завершает работу, когда какой-либо шаблон соответствует» - это ключевой момент, и ни один из ответов с более высоким рейтингом не объясняет его так четко и открыто, как вы сделали здесь. Конечно, это есть на странице руководства где-то, и если я Прочитал бы все внимательно, я бы это увидел. Тем не менее, спасибо.
TheDudeAbides
0

Если кто-то ищет это ... Я хотел выполнить синхронизацию только определенных файлов и папок, и мне удалось сделать это с помощью этой команды: rsync --include-from=rsync-files

С rsync-файлами:

my-dir/
my-file.txt

- /*
Паскаль Поллеун
источник
0

Написал эту удобную функцию и вставил в свои сценарии bash или ~/.bash_aliases. Протестировано синхронизацию локально в Linux с awkустановленным bash . Оно работает

selrsync(){
# selective rsync to sync only certain filetypes;
# based on: https://stackoverflow.com/a/11111793/588867
# Example: selrsync 'tsv,csv' ./source ./target --dry-run
types="$1"; shift; #accepts comma separated list of types. Must be the first argument.
includes=$(echo $types| awk  -F',' \
    'BEGIN{OFS=" ";}
    {
    for (i = 1; i <= NF; i++ ) { if (length($i) > 0) $i="--include=*."$i; } print
    }')
restargs="$@"

echo Command: rsync -avz --prune-empty-dirs --include="*/" $includes --exclude="*" "$restargs"
eval rsync -avz --prune-empty-dirs --include="*/" "$includes" --exclude="*" $restargs
}

Преимущества:

короткий, удобный и расширяемый, когда нужно добавить больше аргументов (т.е. --dry-run).

Пример:

selrsync 'tsv,csv' ./source ./target --dry-run
биокибермэн
источник