У меня есть файл .bdf внутри подпапок. Все .bdf имеют одно и то же имя: Loads.bdf
Пример:
/home/user/folderxx/folderxxx/Load.bdf
/home/user/folderxx/folderxxx/Load.bdf
Мне нужно найти (и скопировать в новую папку) все файлы Load.bdf и переименовать их, указав путь к ним.
Пример: После предполагаемой операции должно появиться что-то вроде этого.
folder001_folderAAA_Load.bdf
folder002_folderBBB_Load.bdf
решение1
Для этого я бы использовал mcp
инструмент из пакета («multiple move»):mmv
mcp '/home/user/*/*/Load.bdf' '#1_#2_Load.bdf'
#1
, и т. д #2
. во второй строке будут заменены содержимым соответствующего 1-го, 2-го и т. д. подстановочного знака из первой строки. Обратите внимание, что путь заключен в одинарные кавычки, чтобы подстановочные знаки интерпретировались mcp
, а не оболочкой.
С помощью показанной команды файлы будут скопированы в текущий каталог. Если заменить mcp
на mmv
, файлы будут перемещены.
решение2
Используя prename
(псевдоним rename
во многих системах), это можно сделать без многократных запусков mv
или cp
:
cd /home/user
find . -type f -name 'Loads.bdf' -exec \
prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +
Удалите, -n
когда будете уверены, что перемещаете нужные вам файлы.
Обновлять
Чтобы скопировать файлы вместо их перемещения, самый быстрый способ — сначала скопировать с помощью cpio
или pax
, а затем переименовать, как и раньше. Например (с помощью GNU cpio
):
cd /home/user
find . -type f -name 'Loads.bdf | cpio -p --make-directories destination
cd destination
find . -type f -name 'Loads.bdf' -exec prename -n 's:^./::; s:/:_:g' {} +
Обратите внимание, что хотя pax
это и POSIX, и LSB, и cpio
больше не POSIX, cpio
это по-прежнему программа, которая обычно встречается во многих системах.
Для обработки имен файлов с символами новой строки с помощью GNU / find
можно cpio
добавить -print0
и find
к -0
.cpio
Обновление 2
Решение pax
состоит из одной строки (не включая cd
):
cd /home/user
find . -name 'Loads.bdf' | cut -d/ -f 2- | pax -rws ':/:_:g' destination
Или для любого имени файла (и GNU find
):
find /home/user -name 'Loads.bdf' -printf '%P\0' | pax -0rws ':/:_:g' destination
решение3
Если вам нужно сделать это в системе, в которой нет инструментов, упомянутых в некоторых других ответах (например, mcp и mmv или prename), и вы хотите сделать это полностью в оболочке, вы можете сделать что-то вроде:
#!/usr/bin/env bash
oldpath="/home/user"
newpath="/home/user/newfolder"
for file in $(find $oldpath -type f -name Load.bdf); do
shortname=${file#$oldpath/}
newname="$newpath/${shortname//\//_}"
if [ -f $newname ]; then
echo "$newname already exists."
else
echo "copy: $file"
echo " --> $newname"
cp $file $newname
fi
done
Этот скрипт найдет все файлы, указанные Load.bdf
в oldpath
каталоге, преобразует имена каталогов в новое имя файла и скопирует их в ваш целевой каталог. Мы также можем проверить наличие уже скопированных файлов, если вам нужно запустить его больше одного раза, и нам не нужно копировать все файлы снова.
Результирующая структура каталогов будет выглядеть следующим образом:
bash$ find . -type f
/home/user/folder001/folderAAA/Load.bdf
/home/user/folder002/folderBBB/Load.bdf
/home/user/folder003/folderCCC/Load.bdf
/home/user/newfolder/folder001_folderAAA_Load.bdf
/home/user/newfolder/folder002_folderBBB_Load.bdf
/home/user/newfolder/folder003_folderCCC_Load.bdf
решение4
env - sh <<\SCRIPT
t=/home/user/target f=folder
cd "${t%/*}" && mkdir -p "$t"
set -- $f??/$f???/Load.BDF
while [ -e "$1" ] ; do
cp "$1" "$t/$(IFS=/
printf '%s_%s_%s\n' $1)"
shift ; done
SCRIPT
Я думаю, что это полностью переносимый скрипт оболочки, и он довольно просто реализован, хотя поначалу у меня были сомнения.