Мне нужно сделать копию всех папок в / parent (в новое место), но только если в нем есть 123.dat - в этом случае мне тоже нужно скопировать папку, но ни один из других файлов, которые она содержит .
Так что это:
|parent
| |a
| | 123.dat
| | 456.dat
| |b
| | 123.dat
| | 789.dat
| |c
| | 456.dat
| | 789.dat
становится:
|parent
| |a
| | 123.dat
| |b
| | 123.dat
Как мне сделать это в Linux? Эта область не является моей компетенцией, и до сих пор я не добивался успеха в попытках найти что-то подобное.
Файл/Структура папок:
$ find src | sort
src
src/a
src/a/123.dat
src/a/456.dat
src/b
src/b/123.dat
src/b/768.dat
src/c
src/c/456.dat
src/c/768.dat
Копия, соответствующая файлам, сохраняя относительный путь (мелкий, не идя глубже, чем 1 папка):
Команда:
$ (cd src && cp -v --parents */123.dat ../dest)
Вывод:
a -> ../dest/a
'a/123.dat' -> '../dest/a/123.dat'
b -> ../dest/b
'b/123.dat' -> '../dest/b/123.dat'
(
и )
для не изменения исходного рабочего каталога при использовании cd
. Я должен был войти src
перед выполнением cp
для не создания src/
как основывают dir в dest
.Альтернативный подход (использование find
с корректируемым пределом глубины):
Команда:
$ (cd src && find . -maxdepth 2 -type f -name '123.dat' -exec cp -v -t "../dest" --parents {} +)
Вывод:
./b -> ../dest/./b
'./b/123.dat' -> '../dest/./b/123.dat'
./a -> ../dest/./a
'./a/123.dat' -> '../dest/./a/123.dat'
Примечания:
(
и )
для не изменения исходного рабочего каталога при использовании cd
. Я должен был войти src
перед выполнением find
для не создания src/
как основывают dir в dest
.-type f
удостоверяться только файлы с именем 123.dat
рассматриваются, не каталоги, которые, оказывается, имеют то имяАльтернативный подход (использование rsync
, без ограничения глубины):
Команда:
$ rsync -rv --include=123.dat --include='*/' --exclude='*' --prune-empty-dirs src/ dest
Вывод:
building file list ... done
created directory dest
./
a/
a/123.dat
b/
b/123.dat
sent 205 bytes received 90 bytes 590.00 bytes/sec
total size is 0 speedup is 0.00
Двойная проверка:
$ find dest
dest
dest/b
dest/b/123.dat
dest/a
dest/a/123.dat
Примечания:
/
из src/
является намеренным, так, чтобы только содержание папки было скопировано, не сама папка.--exclude='*'
исключает все по умолчанию--include='*/
переопределяет исключение и включает все папки--include='123.dat'
переопределяет исключение и включает файлы (и папки) с именами '123.dat'--prune-empty-dirs
удостоверяется, что никакие пустые папки не создаются (например. c
)Один подход должен сделать новую версию родительского каталога в новом месте, затем скопировать через подкаталоги, если они содержат 123.dat. Это использует globbing функцию оболочки Bash, чтобы найти, что подкаталоги так будут только сразу работать над каталогами ниже родителя. в примере я предположу, что родитель находится в названном каталоге /location1/
и будет перемещаться в /location2/
:
mkdir -p /location2/parent
for d in /location1/parent/*
do if [[ -e "$d"/123.dat ]]; then
cp -r "$d" /location2/parent
done
fi
Как острота CLI, которая была бы:
mkdir -p /location2/parent; for d in /location1/parent/*; do if [[ -e "$d"/123.dat ]]; then cp -r "$d" /location2/parent; done; fi
Возможно улучшить это при помощи find
сделать это более эффективным и добавить много подкаталоги уровня, или путем помещения исходного каталога, целевого каталога и файла для поиска в переменные. Это должно сделать то, в чем Вы нуждаетесь на данный момент.
Для копирования каталога, если это содержит конкретный файл но не копирует какой-либо из других файлов, существует меньше, чем изящное решение, которое требует cd
луг в исходный каталог, cd -
часть в конце возвращает Вас Вашему исходному каталогу:
mkdir -p /location2/parent; cd /location1/parent/ && for d in ./*; do if [[ -e "$d"/123.dat ]]; then cp --parents "$d"/123.dat /location2/parent/; fi ; done; cd -
Как мультилиния:
mkdir -p /location2/parent
cd /location1/parent/ && for d in ./*
do
if [[ -e "$d"/123.dat ]]; then
cp --parents "$d"/123.dat /location2/parent/
fi
done
cd -