42

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?

  • Do you want to keep the directory structure? You want to move the directories, or just the zip files? – jordanm Mar 10 '13 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. – InquilineKea Mar 10 '13 at 21:33
53

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 {} \;
  • First find command above worked in bash, but had to change to find . -name etc to get it to work. – JeffThompson May 29 '17 at 19:08
  • 1
    @Jeff . is implicit for GNU find but not for others, I've added it explicitly. – Gilles May 29 '17 at 20:31
13

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

mkdir ./zipfiles
find . -name "*.zip" -exec mv "{}" ./zipfiles \;
3

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.

  • what do you mean by relative paths? – Kunok Jan 3 '18 at 11:44
2

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.

  • what does ; do? – Francesco Boi Jul 23 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 Aug 10 at 2:59
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

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.

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.