Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a .bdf file inside subfolders. All the .bdf have the same name: Loads.bdf

Example:

/home/user/folderxx/folderxxx/Load.bdf
/home/user/folderxx/folderxxx/Load.bdf

I need to find (and copy to a new folder) all Load.bdf files and rename them with its path name.

Example: After the intended operation, it should show something like this.

folder001_folderAAA_Load.bdf
folder002_folderBBB_Load.bdf
share|improve this question

5 Answers 5

I would use the mcp tool from the mmv ("multiple move") package for that:

mcp '/home/user/*/*/Load.bdf' '#1_#2_Load.bdf'

The #1, #2 etc. in the second string will be replaced by the contents of the corresponding 1st, 2nd etc. wildcard from the first string. Note that the path is in single quotes so that the wildcards are interpreted by mcp, not by the shell.

With the command shown, the files will be copied to the current directory. If you replace mcp with mmv, the files will be moved instead.

share|improve this answer
    
Double quoted strings also don't have wildcard expansion, at least in bash. –  Daniel Beck Jun 17 at 0:04

Using prename (aliased to rename on many systems) it is possible to do this without multiple runs of mv or cp:

cd /home/user
find . -type f -name 'Loads.bdf' -exec \
  prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +

Remove the -n when you are sure this is moving the files you want.

Update

To copy the files instead of moving them, the fastest way is to copy first with cpio or pax, then to rename as before. Eg (with 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' {} +

Note that while pax is both POSIX and LSB and cpio is no longer POSIX, cpio is still the program which is commonly found many systems.

To handle filenames with newlines with GNU find/cpio it is possible to add -print0 to find and -0 to cpio.

Update 2

The pax solution is a one-liner (not including the cd):

cd /home/user
find . -name 'Loads.bdf' | cut -d/ -f 2- | pax -rws ':/:_:g' destination

Or for any filename (and GNU find):

find /home/user -name 'Loads.bdf' -printf '%P\0' | pax -0rws ':/:_:g' destination
share|improve this answer
    
There are two renames, the perl one (aka prename, but called rename by default in Ubuntu at least), and the other one that doesn't use regex (known as rename on Arch and Red Hat). Also, -execdir is preferred to -exec (see man find). Finally, doesn't this command move the files, not copy them? –  Sparhawk Jun 16 at 15:15
    
@Sparhawk, yes that's why I specified prename. Although I missed the 'copy` part in the question. –  Graeme Jun 16 at 15:17
    
Ah okay (was that an edit?). Perhaps I just read it wrong. –  Sparhawk Jun 16 at 15:17
    
@Sparhawk, no edit. Good call on the move vs copy though I have added an updated solution now. –  Graeme Jun 16 at 15:35
1  
@Tim, updated with the pax solution, it has its own find/replace option. –  Graeme Jun 16 at 15:57

If you happen to need to do this on a system that doesn't have the tools mentioned in some of the other answers (like mcp and mmv, or prename), and you want to do it entirely in the shell, you can do something like:

#!/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

This script will find all the files named Load.bdf in the oldpath directory, munge the directory names into a new filename, and copy them to your destination directory. We can also check for the existence of files already copied, in case you need to run it more than once, and we don't need to copy all the files again.

The resulting directory structure would end up looking like:

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
share|improve this answer
    
thank you all for your information. i got lot more information than what i need. thank you again. –  user3739330 Jun 16 at 18:39

In zsh, it's easy with zmv.

autoload -U zmv
cd /home/user
zmv '*/*/*' '${1//\//_}'
share|improve this answer
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

I think this is all fully portable shell script - and it's pretty simply done, though I had my doubts at first.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.