12

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?

2 Answers 2

15

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

find -type f -exec mv {} collection/ \;
6
  • 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, 2011 at 12:24
  • Come to think of it, it seems like I read your question wrong :) Sorry.
    – loevborg
    May 7, 2011 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, 2011 at 12:39
  • 1
    a faster variation of this answer is find -type f -print0|xargs -0r mv -it colection/
    – hildred
    Mar 4, 2014 at 17:20
  • Could you explain the components of the command? Also, how will this handle duplicate files? May 12, 2020 at 0:38
6

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

4
  • 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 :) May 7, 2011 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, 2011 at 13:18
  • Lekensteyn, you're right. I updated the answer now that I've understood the question.
    – loevborg
    May 7, 2011 at 13:45
  • 2
    Wonderful answer, too bad that it's not particularly relevant to the question :).
    – crazy2be
    May 7, 2011 at 18:21

You must log in to answer this question.

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