moving files and folders to a subfolder

18,616

Solution 1

After more digging and experimentation. I found the answer: -prune is used to avoid recusing into sub-directories. ! -name is used to exclude the target sub-directory, and then exec executes the move operation. The {} is replaced with file/directory names from the find command.

find /my/path/* -prune ! -name subfolder -exec mv {} /my/path/subfolder/. +

Solution 2

mv * subfolder 

Of course, it will fail moving the "subfolder" directory into itself, but everything else will move

Solution 3

Solutions that use * (expanded by shell) won't work with too many objects in /my/path/. In such case you'll get:

argument list too long

This approach doesn't use *:

cd /my/path/ &&
find . -mindepth 1 -maxdepth 1 ! -name subfolder -exec mv -t subfolder/ {} +

Unfortunately -mindepth and -maxdepth options of find are not POSIX-compliant; neither -t option of mv is, I think.

This variant should satisfy POSIX:

cd /my/path/ &&
find . ! -name . -prune ! -name subfolder -exec mv {} subfolder/ \;

(I adapted this Unix & Linux SE answer). Sadly it calls mv for every object found, thus it's slow.


Fast alternative approach, if only you can create directories anew (initially neither /my/path/subfolder/ nor /my/subfolder/ should exist):

  • rename path/ to subfolder/,
  • recreate path/,
  • move subfolder/ into path/.

Note on inode-based filesystem this should be equally fast, no matter how many objects there are in path/. The code:

cd /my/ &&
test ! -e subfolder/ && mv path/ subfolder/ &&
mkdir path/ &&
mv subfolder/ path/

In this case I used && a lot to emphasize the procedure should abort if any of its steps fails. However this approach is inconvenient if you need path/ or subfolder/ to have non-default permissions, ownership etc.

Solution 4

Although i'm a bit late, I was in the same situation and came with a different solution that won't trigger anything to stdout, stderr or provide non-null exit code.

In case it can help someone:

items=(*)
mkdir subfolder
mv ${items[*]} subfolder

In case you have filenames containing spaces, you will have to add IFS='' at the first line to properly escape them (which was my case).

Solution 5

The simplest way to do this is:

mv !(subfolder) subfolder

'!' means NOT, similar to programming languages, where mv will move all files and folders to the required subfolder with the exception of the subfolder.

Additional things like moving hidden folders and dot folders are described here: https://askubuntu.com/questions/91740/how-to-move-all-files-in-current-folder-to-subfolder

Share:
18,616

Related videos on Youtube

hebbo
Author by

hebbo

Updated on September 18, 2022

Comments

  • hebbo
    hebbo over 1 year

    I would like to move all files and folder from one directory to one of its subfolders. How do I do that?

    I am using BusyBox and linux.

    ex:

    move all files and folder in /my/path/ to /my/path/subfolder/.

    Copy, and then delete solutions are not affordable.

    Thanks.

    • Xen2050
      Xen2050 about 6 years
      A GUI file manager might be a good option, shouldn't have any surprises
  • hebbo
    hebbo about 6 years
    Is this in mv's specification? or is this hoping to be lucky? it may stop at first failure and I will end up with some of files and folder being moves but not all.
  • Gradyn Wursten
    Gradyn Wursten about 6 years
    @hebbo it will not stop at first failure
  • Xen2050
    Xen2050 about 6 years
    * excludes hidden files (or so testing shows me, though there's probably a setting for it somewhere)
  • Kamil Maciorowski
    Kamil Maciorowski about 6 years
    What find implementation can do this? Normally … -exec mv {} /my/path/subfolder/. + fails because you cannot separate {} and +, they must be at the very end: {} +; this is not the case with \;.
  • Razetime
    Razetime about 6 years
    This may be unnecessarily complex.
  • hebbo
    hebbo about 6 years
    I am using busyBox
  • hebbo
    hebbo about 6 years
    This did not work with the version of find I am using.
  • Matěj Kříž
    Matěj Kříž almost 5 years
    Files with name starting with a dot (like .git) are excluded to. To hotfix this run mv .* subfolder (mv dot-start subfolder)
  • Triamus
    Triamus over 4 years
    didnt work for me
  • loopmode
    loopmode over 2 years
    This is really useful. However, items=(*) ignores dot-files like .gitignore
  • loopmode
    loopmode over 2 years
    (Cannot edit comment after 5 minutes) However, (* .[!.]*) seems to work fine for me: IFS='';items=(* .[!.]*);mkdir subfolder;mv ${items[*]} subfolder