Переименование файлов с указанием пути

Переименование файлов с указанием пути

У меня есть файл .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

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

Связанный контент