5

I have a directory that contains many subdirectories. The subdirectories contain lots of types of files with different file extensions. I want to move (not copy) all the files of one type into a new directory. I need all these files to be in the same directory, i.e. it needs to be flat.

(My use case is that I want to move ebooks called *.epub from many directories into a single folder that an EPUB reader can find.)

1
  • For that use case: Maybe it's better not to move the files but to link them? May 6, 2013 at 22:10

3 Answers 3

12

In zsh, you can use a recursive glob:

mkdir ~/epubs
mv -- **/*.epub ~/epubs/

In bash ≥4, run shopt -s globstar (you can put this in your ~/.bashrc) then the command above. In ksh, run set -o globstar first.

With only POSIX tools, run find:

find . -name '*.epub' -exec mv {} ~/epubs \;
1
  • Note that bash (and fish) contrary to zsh or ksh93 do follow symlinks when descending the directory tree (see here for details). find will include dot files and follow dotdirs, not **. With **, you may run into the too many args limit which zsh and ksh93 have work around for, but not bash. May 7, 2013 at 5:42
6

Try doing this :

mkdir ../new_dir
find . -type f -name '*.epub' -exec mv {} ../new_dir/ \;

if all the files are named name.epub, then you need to increment a variable like this (using )

mkdir ../new_dir
find . -type f -name '*.epub' |
    while read a; do
        ((c++))
        base="${a##*/}"
        mv "$a" "../new_dir/${base%.epub}_$(printf %.03d $c).epub"
    done
2
  • That's going to end up with a lot of error messages if the target directory is part of the search tree... Thus if you want to create it there above all then use -prune at least. May 6, 2013 at 22:13
  • post edited accordingly May 7, 2013 at 9:00
3

Using bash under Linux:

shopt -s nullglob globstar
mv -t ~/epub_directory ~/big_dir/**/*.epub
3
  • Note that there's nothing Linux-specific in there. mv -t is GNU specific though (and most Linux distributions have GNU mv as their mv). There's no reason to be using mv -t here though. May 7, 2013 at 5:54
  • @StephaneChazelas I added that. In practice, for most people, GNU <-> Linux || Cygwin (as opposed to OSX, *BSD, Solaris). I didn't see the point of using mv -t either but didn't feel comfortable changing that (it's a matter of style rather than correctness). May 7, 2013 at 8:07
  • I originally had something a bit more complicated piping in to xargs mv -t dir. I left that form of mv here May 7, 2013 at 10:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .