Рекурсивные копии файлов в bash сохранении дерева каталогов - PullRequest
1 голос
/ 08 апреля 2020

Мое приложение X организует проекты в папки с указанным деревом c. Определен первый уровень дерева (жесткое ограничение), в то время как все содержимое свободно организовано.

Моя цель состоит в том, чтобы перебирать все папки дерева проекта, анализировать имена папок, чтобы получить цели на основе условий, затем скопируйте выбранные цели в новую папку проекта, сохраняя древовидную структуру, так что приложение X не будет жаловаться.

До сих пор я придумал это:

cp -pr `find . -type d | grep -i targetstring` ../newProjectFolder/

Это имеет проблемы: 1) не сохраняет дерево папок; 2) выдает много ошибок cp: cannot stat (см. Также this ). Это не просто работает, как задумано.

Более того, синтаксический анализ вывода find - это , как правило, плохая идея .

Мне удалось преодолеть первую проблему с --parents как предложено здесь . Тем не менее, я копирую намного меньше, чем мне нужно из-за пункта 2, так что не решение, в конце концов.

Я ищу однострочное решение проблемы . Скриптное решение доступно здесь . РЕДАКТИРОВАТЬ: , поскольку это было помечено как дубликат предоставленной ссылки, я перефразирую немного: я хочу решение, в котором мне не нужно явно указывать время и, если-еще, мой путь к нему. Трубопроводы find и grep предоставляют все места для копирования, но cp жалуется. Как нам передать их на cp, не жалуясь?

Я искал что-то, используя -exec как suggersted здесь , и придумал следующее, которое не работает (ничего не копируется) (копируется только частичная древовидная структура, а файлы внутри этой структуры копируются, только если они также соответствуют регулярному выражению):

find . -regex ".*targetstring.*" -exec cp -rp --parents \{\} ../newProjectFolder \;

1 Ответ

2 голосов
/ 09 апреля 2020

«одна строка», но sed не будет работать для новых строк $'\n' в имени файла

при условии, что вы cd войдете в папку проекта и запустите find . всегда с .
будет соответствовать targettring (на любом уровне) и скопирует все (содержащее) дерево из первого уровня

пример дерева
searchProjectFolder/some/parent/folders/matched/targetstring/foo/bar/

при поиске *targetstring* внутри searchProjectFolder/ будет скопирована вся папка ./some (включая все файлы и подпапки)

, а -regex или -ipath распечатает все файлы, -iname распечатает только соответствующую папку targetstring/. вы можете ограничить поиск указанными c уровнями с -mindepth 5 и -maxdepth 5 и указать целевой тип для соответствия папок только с -type d (но давайте уберем эту опцию для сейчас)

создайте newProjectFolder и запустите find для дерева примеров

mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*"

результат для дерева примеров равен

./some/parent/folders/matched/targetstring

now find результат передается в grep, поэтому мы можем обрезать строку только до первого уровня

find . -iname "*targetstring*" | grep -o ^\./[^/]*

результат в примере дерева равен

./some

вместо grep мы можем использовать sed, чтобы заключить в кавычки "имя папки" (может иметь пробелы)

find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'

результат на примере дерева равен

"./some"

наконец, давайте cp все папки с eval, потому что "имена папок" заключены в кавычки. это «однострочник»:

eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder

результат на примере дерева

cp -a "./some" ../newProjectFolder

для лучшего понимания я объясню sed

sed -n 's,^\(\./[^/]*\).*,"\1",p'
sed -n 's, ^  \(  \.  /  [^/]*  \)  .* , "\1" ,p'

-n = не печатать ввод
p in ,p' = печатать только совпадающий вывод

\1 = печатать первую группу захвата
\( = начало группы захвата
\) = конец группы захвата

^ = совпадение начала только строки
\. = одна точка (.)
/ = одиночный sla sh (разделитель пути)
[^/] = любой отдельный байт, но не sla * sh
[^/]* = любая строка, не содержащая косую черту
. = одиночный байт
.* = любая строка

, поэтому (первая) группа захвата (начало строки)
./example string

группа захвата цитируется ("\1")
"./example string"


edit:

еще одна "настоящая" однострочная строка, если вы хотите скопировать папку targetstring/ (с родительским деревом)

mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;

результат в примере дерева:

cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...