97

I have a bunch of .zip files in several directories:

Fol1/Fol2
Fol3
Fol4/Fol5

How would I do move them all to a common base folder?

3
  • Do you want to keep the directory structure? You want to move the directories, or just the zip files?
    – jordanm
    Commented Mar 10, 2013 at 21:31
  • I just want to move the zip files. I don't really care about the directories - they can be left alone or deleted. Commented Mar 10, 2013 at 21:33
  • Have you not "accepted" an answer here because none of them addressed your question?
    – Seamus
    Commented Nov 21, 2023 at 19:38

7 Answers 7

132

Go to the toplevel directory of the tree containing the zip files (cd …), then run

mv **/*.zip /path/to/single/target/directory/

This works out of the box in zsh. If your shell is bash, you'll need to run shopt -s globstar first (you can and should put this command in your ~/.bashrc). If your shell is ksh, you'll need to run set -o globstar first (put it in your ~/.kshrc).

Alternatively, use find, which works everywhere with no special preparation but is more complicated:

find . -name '*.zip' -exec mv {} /path/to/single/target/directory/ \;

If you want to remove empty directories afterwards, in zsh:

rmdir **/*(/^Fod)

In bash or ksh:

rmdir **/*/

and repeat as long as there are empty directories to remove. Alternatively, in any shell

find . -depth -type d -empty -exec rmdir {} \;
6
  • First find command above worked in bash, but had to change to find . -name etc to get it to work. Commented May 29, 2017 at 19:08
  • 1
    @Jeff . is implicit for GNU find but not for others, I've added it explicitly. Commented May 29, 2017 at 20:31
  • 1
    WARNING If directory doesn't exist in /path/to/single/target/, the mv command will rename each file to directory and each one will overwrite the last, essentially deleting all your files.
    – Alain
    Commented Mar 10, 2020 at 13:07
  • 1
    @Alain Indeed. I've edited my answer to use directory/ which causes an error if the directory doesn't exist or if it's a regular file. Commented Mar 10, 2020 at 13:50
  • Thanks @Gilles'SO-stopbeingevil' - missed one though. The second command (using find) has the same problem. That's actually the one that bit me.
    – Alain
    Commented Mar 10, 2020 at 14:18
23

If you only want to move the .zip files, you could do something like

mkdir ./zipfiles
find . -name "*.zip" -exec mv "{}" ./zipfiles \;
2
  • 2
    This is the best way to do it. Simple and works if you have find. Another cool thing is if you want to move any kind of file you could use the type argument to find, such as: find . type f -exec mv "{}" dest-dir \;
    – ranu
    Commented Dec 4, 2019 at 19:17
  • find command also found moved files. find . -path "./zipfiles" -prune -o -name "*.zip" -exec mv "{}" ./zipfiles \; would avoid this, imo. Commented Jan 29 at 5:11
5

This one is safe when moving data and error free which supported most of all distro regardless versions. This command will scan subdirectories and then move or copy to your new destination directory.

find . -name *.flac -exec mv '{}' "./flac/" ";"
  • Run this command at the main directory that contains sub-directories with the files you wish to move.
  • Where you can change *.flac to anything like *.zip in your case. Or *.doc just any extension works.
  • and mv is the command to move files, or you can use cp to copy data instead of moving.
  • ./flac/ is the destination directory that I want to move all FLAC files to. You can also give it a full path like /home/myid/flac/

Full example. (in this case, there are many subdirectories with music artist name at /home/myid/Music/ and then FLAC files are all over different subdirectories level. Since I don't need artist folders but want to have all FLAC files into one directory at /home/myid/Music/flac/

cd /home/myid/Music
mkdir flac
find . -name *.flac -exec mv '{}' "./flac/" ";"
cd flac
ls

Then it will display all FLAC files.

5
  • what does ; do? Commented Jul 23, 2019 at 8:09
  • @FrancescoBoi it make sure to wait until the bash command in the same line finish its job. and then move on to the next line of bash commands. This is useful for commands that contains scripts like .pl or python because bash will just run it and then jump to the next line, so to be safe, i use ; after the commands that takes time or script, in case bash skips it.
    – Seandex
    Commented Aug 10, 2019 at 2:59
  • This is a not very useful repeat of previous answers but with FLAC added, which was not in the question Commented Aug 10, 2020 at 15:52
  • @brianlmerritt I mentioned "compatible" while other answers are not compatible, and the question mentioned "certain" extension so I can use any extension in example. read the question again. or have experience on multiple distro.
    – Seandex
    Commented Aug 24, 2020 at 5:50
  • @brianlmerritt and there is the reason why 4 people found mine useful after trying previous answers, Try to tackle the other 3 answers that repeat as well if you have enough experience on bash and find out what will cause an error when it comes to multi distro.
    – Seandex
    Commented Aug 24, 2020 at 7:13
4

If you're using bash version 4 or higher or zsh you can also use recursive globbing:

mv **/*.zip /path/to/move/zip/files/to

This will move ONLY the files and not their relative paths, so collisions might occur.

1
  • what do you mean by relative paths?
    – Kunok
    Commented Jan 3, 2018 at 11:44
2

Assuming you have the GNU versions of find and mv, the following will be more efficient than the existing find-based answers:

find . -name '*.zip' -exec mv --target-directory='/path/to/outputdir' '{}' +

Using a + at the end of the find -exec means that a list of files will be passed to the mv command, rather than executing one mv command per file found. However, a limitation of this is that you can only place the '{}' at the end of the command, which necessitates the use of the mv --target-directory option, and as far as I know that's a GNU-ism.

0

As a bash hack, you could use the power of tar:

(cd origin/;find . -exec file --mime-type "{}" \;|grep "application/zip"|cut -d ':' -f 1|xargs tar cf -)|(cd target/; tar xf -) && rm -fr origin/

This has the advantage that it does not depend on file extensions, since it uses the file command to choose the files to move and it preserves the directory structure, but it doesn't work with paths containing spaces.

The final rm is there just to remove the original files (becouse @InquilineKea tolds that he doesn't care about the original folder in the comment).

Of course this is particularly suitable if the origin/ and target/ folders are on different disks. Otherwise the other solutions proposed are more efficient (even if they rely on naming conventions, instead of file's content).

0

In addition to Gilles' advice where he suggested

mv **/*.zip /path/to/single/target/directory/

you may get feedback saying

mv: will not overwrite just-created

because there might be duplicate file names being copied to the target directory.

If you add --backup=numbered this will create numbered backup files with duplicate names.

e.g. duplicate-name.zip.~1~

You must log in to answer this question.

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