Рекурсивно копировать папку, исключая некоторые папки
197
Я пытаюсь написать простой сценарий bash, который будет копировать все содержимое папки, включая скрытые файлы и папки, в другую папку, но я хочу исключить некоторые конкретные папки. Как я мог этого добиться?
Я представляю что-то вроде поиска. -name * передается в grep / v "exclude-pattern", чтобы отфильтровать ненужные файлы, а затем передается в cp, чтобы сделать копию.
i_am_jorf
1
Я пытался сделать что - то подобное, но не мог понять, как использовать ф с трубкой
trobrock
1
Это, вероятно, следует перейти к супер пользователя. Команда, которую вы ищете, это xargs. Вы также можете сделать что-то вроде двух смол, соединенных трубкой.
Кайл Батт
1
Может быть, уже поздно, и он не дает точного ответа на вопрос, но вот совет: если вы хотите исключить только непосредственных дочерних элементов каталога, вы можете воспользоваться преимуществами сопоставления шаблонов bash, например,cp -R !(dir1|dir2) path/to/destination
Борис Д. Теохаров
1
Обратите внимание, что !(dir1|dir2)шаблон extglobдолжен быть включен ( shopt -s extglobчтобы включить его).
Обратите внимание, что использование sourceи source/разные. Конечный слеш означает копирование содержимого папки sourceв destination. Без косой черты это означает, что скопируйте папку sourceв destination.
В качестве альтернативы, если у вас есть много каталогов (или файлов) для исключения, вы можете использовать --exclude-from=FILE, где FILE- имя файла, содержащего файлы или каталоги, которые нужно исключить.
--exclude может также содержать символы подстановки, такие как --exclude=*/.svn*
Я предлагаю добавить --dry-run, чтобы проверить, какие файлы будут скопированы.
Лоретопариси
1
@AmokHuginnsson - Какие системы вы используете? Rsync включен по умолчанию во все известные мне основные дистрибутивы Linux, включая RHEL, CentOS, Debian и Ubuntu, и я верю, что он также во FreeBSD.
SiliconRockstar
1
Для дистрибутивов, производных от RHEL: yum install rsync или для выпусков на основе Debian: apt-get install rsync. Если вы не строите свой сервер на основе собственного оборудования, это не проблема. rsync по умолчанию устанавливается на мои блоки Amazon EC2, а также на мои блоки ZeroLag и RackSpace.
silicrockstar
2
Rsync кажется очень медленным по сравнению с cp? По крайней мере, это был мой опыт.
Кожо
2
Например, чтобы игнорировать git dir:rsync -av --exclude='.git/' ../old-repo/ .
nycynik
40
Используйте смолу вместе с трубкой.
cd /source_directory
tar cf ---exclude=dir_to_exclude .|(cd /destination && tar xvf -)
Вы можете даже использовать эту технику через ssh.
При таком подходе вначале копируется целевой источник (и исключаются отдельные каталоги в архиве), а затем распаковывается его в целевой. Не рекомендуется!
Воутер Дондерс
4
@ Вальдхери, ты не прав. Это лучшее решение. Он выполняет именно то, что запрашивал OP, и работает по умолчанию при установке большинства * nix-подобных ОС. Тарирование и распаковка выполняются на лету без артефактов файловой системы (в памяти), стоимость этого tar + untar незначительна.
AmokHuginnsson
@WouterDonders Tar - минимальные накладные расходы. Сжатие не применяется.
Кайл Батт
9
Вы можете использовать findс -pruneопцией.
Пример из man find:
cd / source-dir
найти . -name .snapshot -prune -o \ (\! -name * ~ -print0 \) |
cpio -pmd0 / dest-dir
Эта команда копирует содержимое / source-dir в / dest-dir, но пропускает
файлы и каталоги с именем .snapshot (и все, что в них). Это также
пропускает файлы или каталоги, чье имя оканчивается на ~, но не их
палатки. Конструкция -prune -o \ (... -print0 \) довольно распространена.
Идея в том, что выражение перед -prune соответствует вещам, которые
быть обрезанным. Однако само действие -prune возвращает true, поэтому
следующий -o гарантирует, что правая часть вычисляется только для
те каталоги, которые не были сокращены (содержимое сокращенного
каталоги даже не посещаются, поэтому их содержимое не имеет значения).
Выражение справа от -o приведено только в скобках
для ясности. Подчеркивается, что действие -print0 выполняется только
за вещи, к которым не было применено -прун. Поскольку
условие `` и 'между тестами связывает более тесно, чем -o, это
в любом случае по умолчанию, но скобки помогают показать, что происходит
на.
Приостановлено до дальнейшего уведомления. источник
Реквизиты для поиска очень актуального примера прямо из man-страницы.
Дэвид М
Выглядит действительно хорошо! Это также доступно в онлайн-документах . К сожалению, cpioеще не был упакован для MSYS2.
underscore_d
3
Вы можете использовать tar с параметром --exclude, а затем распаковать его в месте назначения. например
cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination
cd /destination
tar xvf test.tar
см. справочную страницу tar для получения дополнительной информации
Извините, но я действительно не понимаю, почему 5 человек проголосовали за это, когда оно было признано непроверенным и, похоже, не работает над простым тестом: я попробовал это в подкаталоге /usr/share/iconsи сразу же получил, find: paths must precede expression: 22x22где последний является одним из подкаталогов в нем , Моя команда была find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(по общему признанию, я нахожусь на MSYS2, так действительно /mingw64/share/icons/Adwaita, но я не могу видеть, какова ошибка MSYS2)
underscore_d
0
EXCLUDE="foo bar blah jah"
DEST=$1
for i in*dofor x in $EXCLUDE
doif[ $x != $i ];then
cp -a $i $DEST
fidonedone
Это неверно Несколько проблем: Как написано, он скопирует файл, который не должен быть исключен несколько раз (количество исключаемых элементов, которое в данном случае равно 4). Даже если вы попытаетесь скопировать 'foo', первый элемент в списке исключений, он все равно будет скопирован, когда вы доберетесь до x = bar, а я все еще foo. Если вы настаиваете на том, чтобы делать это без уже существующих инструментов (например, rsync), переместите копию в оператор if вне цикла «for x in ...» и сделайте так, чтобы цикл «for x ...» изменил логический оператор в Копия if (true). Это остановит вас от копирования несколько раз.
Эрик Брингли,
0
Вдохновленный ответом @ SteveLazaridis, который потерпит неудачу, вот функция оболочки POSIX - просто скопируйте и вставьте файл с именем cpxв yout $PATHи сделайте его исполняемым ( chmod a+x cpr). [Источник теперь поддерживается в моем GitLab .
#!/bin/sh# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"# limitations: only excludes from "from_path", not it's subdirectories
cpx(){# run in subshell to avoid collisions(_CopyWithExclude"$@")}_CopyWithExclude(){case"$1"in-n|--dry-run){DryRun='echo'; shift;};;esac
from="$1"
to="$2"
exclude="$3"
$DryRun mkdir -p "$to"if[-z "$exclude"];then
cp "$from""$to"returnfi
ls -A1 "$from" \
|while IFS= read -r f;do
unset excluded
if[-n "$exclude"];thenfor x in $(printf "$exclude");doif["$f"="$x"];then
excluded=1breakfidonefi
f="${f#$from/}"if[-z "$excluded"];then
$DryRun cp -R "$f""$to"else[-n "$DryRun"]&& echo "skip '$f'"fidone}# Do not execute if being sourced["${0#*cpx}"!="$0"]&& cpx "$@"
Кажется бесполезным говорить, что чей-то ответ "потерпит неудачу", не объяснив, что с ним не так и как вы это исправите ...
underscore_d
@underscore_d: правда, задним числом, особенно если я не могу вспомнить, что не удалось :-(
go2null
Несколько вещей: (1) он копирует файлы несколько раз и (2) логика все еще копирует файлы для исключения. Выполните циклы, используя i = foo: он будет скопирован 3 раза вместо 4 для любого другого файла, например, i = test.txt.
Эрик Брингли,
1
Спасибо @EricBringley за разъяснение недостатков ответа Стива. (Он все же сказал, что это было непроверено .)
cp -R !(dir1|dir2) path/to/destination
!(dir1|dir2)
шаблонextglob
должен быть включен (shopt -s extglob
чтобы включить его).Ответы:
Используйте rsync:
Обратите внимание, что использование
source
иsource/
разные. Конечный слеш означает копирование содержимого папкиsource
вdestination
. Без косой черты это означает, что скопируйте папкуsource
вdestination
.В качестве альтернативы, если у вас есть много каталогов (или файлов) для исключения, вы можете использовать
--exclude-from=FILE
, гдеFILE
- имя файла, содержащего файлы или каталоги, которые нужно исключить.--exclude
может также содержать символы подстановки, такие как--exclude=*/.svn*
источник
rsync -av --exclude='.git/' ../old-repo/ .
Используйте смолу вместе с трубкой.
Вы можете даже использовать эту технику через ssh.
источник
Вы можете использовать
find
с-prune
опцией.Пример из
man find
:источник
cpio
еще не был упакован для MSYS2.Вы можете использовать tar с параметром --exclude, а затем распаковать его в месте назначения. например
см. справочную страницу tar для получения дополнительной информации
источник
Похоже на идею Джеффа (не проверено):
источник
/usr/share/icons
и сразу же получил,find: paths must precede expression: 22x22
где последний является одним из подкаталогов в нем , Моя команда былаfind . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/
(по общему признанию, я нахожусь на MSYS2, так действительно/mingw64/share/icons/Adwaita
, но я не могу видеть, какова ошибка MSYS2)Непроверенные ...
источник
Вдохновленный ответом @ SteveLazaridis, который потерпит неудачу, вот функция оболочки POSIX - просто скопируйте и вставьте файл с именем
cpx
в yout$PATH
и сделайте его исполняемым (chmod a+x cpr
). [Источник теперь поддерживается в моем GitLab .Пример использования
источник