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.)

johntait.org
  • 1,322
  • 4
  • 12
  • 19

3 Answers3

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 \;
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • Note that `bash` (and `fish`) contrary to zsh or ksh93 do follow symlinks when descending the directory tree (see [here](http://unix.stackexchange.com/a/62665/22565) 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`. – Stéphane Chazelas May 07 '13 at 05: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
Gilles Quénot
  • 31,569
  • 7
  • 64
  • 82
3

Using bash under Linux:

shopt -s nullglob globstar
mv -t ~/epub_directory ~/big_dir/**/*.epub
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
glenn jackman
  • 84,176
  • 15
  • 116
  • 168
  • 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. – Stéphane Chazelas May 07 '13 at 05: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). – Gilles 'SO- stop being evil' May 07 '13 at 08:07
  • I originally had something a bit more complicated piping in to `xargs mv -t dir`. I left that form of mv here – glenn jackman May 07 '13 at 10:59