I am trying to collect all the files under the current directory and all the subdirectories to one directory. I am trying something like the following

find -type f -exec mv {} collection/{} \; 

the above command won't work because the second {} gives the full path, how can I collect all the files?


Remove the {} from mv, mv will take it as target directory ignoring any parent directories:

find -type f -exec mv {} collection/ \;
  • ohh that didn't occur to me . thanks :) – Bunny Rabbit May 7 '11 at 10:56
  • As I say in my answer to the question, this is potentially a bad idea. Maybe using the argument -maxdepth 1 would help. – loevborg May 7 '11 at 12:24
  • Come to think of it, it seems like I read your question wrong :) Sorry. – loevborg May 7 '11 at 12:25
  • @loevborg: I've added "recursively" to the title now. If there is still confusion, please edit it and improve it :) – Lekensteyn May 7 '11 at 12:39
  • 1
    a faster variation of this answer is find -type f -print0|xargs -0r mv -it colection/ – hildred Mar 4 '14 at 17:20

Instead of using find (which does the job well), you could also use the shell to this end.

Say you want to all files from $PWD to $DEST. The natural attempt would be:

mv $PWD/* $DEST

How does this work? The expression "$PWD/*" expands to the names of all files in that directory. This shell feature is called "globbing". The last argument of mv is the destination directory. If you have very many files, this won't work because the length of the command line is limited.

But the solution has the problem that it omits dot files - or "hidden" files, files and directories whose name start with a ".". To solve this, you have to tell your shell to include dotfiles when globbing. To do this, use

shopt -s dotglob

when using bash (and you probably use bash unless you've changed the default). In this shell, the above command will work for dotfiles as well.

As an aside, in zsh, you have the option to choose this on a case-by-case basis. To do this, put

setopt extendedglob

in your .zshrc. Then you can use

mv $PWD/*(D) $DEST

to move all the files, including dotfiles. (The "D" has the effect of temporarily enabling the "GLOB_DOTS" option).

Now the original question was to move all regular files (not directories) from all subdirectories and their subdirectories to a single directory. This can be accomplished with zsh:

mv $PWD/**/*(D.)

Here the expression **/* makes the globber descend recursively into subdirectories. The D means "also select dotfiles'; the . means "only select regular files, not directories".

  • well i wanted to recurse into all the sub-directories too,but thanks any way the information is useful , come across this situation too a lot of times :) – Bunny Rabbit May 7 '11 at 13:10
  • Actually, find is not overkill for this, globbing will select all matches, not just files, but also directories. If you're worries about performance, you could also use something like: find -type f -exec mv -t collection/ {} +. Consult the manual page on how this works. – Lekensteyn May 7 '11 at 13:18
  • Lekensteyn, you're right. I updated the answer now that I've understood the question. – loevborg May 7 '11 at 13:45
  • 2
    Wonderful answer, too bad that it's not particularly relevant to the question :). – crazy2be May 7 '11 at 18:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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