Split a folder into multiple subfolders in terminal/bash script Split a folder into multiple subfolders in terminal/bash script bash bash

Split a folder into multiple subfolders in terminal/bash script


Try something like this:

for i in `seq 1 20`; do mkdir -p "folder$i"; find . -type f -maxdepth 1 | head -n 2000 | xargs -i mv "{}" "folder$i"; done

Full script version:

#!/bin/bashdir_size=2000dir_name="folder"n=$((`find . -maxdepth 1 -type f | wc -l`/$dir_size+1))for i in `seq 1 $n`;do    mkdir -p "$dir_name$i";    find . -maxdepth 1 -type f | head -n $dir_size | xargs -i mv "{}" "$dir_name$i"done

For dummies:

  1. create a new file: vim split_files.sh
  2. update the dir_size and dir_name values to match your desires
    • note that the dir_name will have a number appended
  3. navigate into the desired folder: cd my_folder
  4. run the script: sh ../split_files.sh


This solution worked for me on MacOS:

i=0; for f in *; do d=dir_$(printf %03d $((i/100+1))); mkdir -p $d; mv "$f" $d; let i++; done

It creates subfolders of 100 elements each.


This solution can handle names with whitespace and wildcards and can be easily extended to support less straightforward tree structures. It will look for files in all direct subdirectories of the working directory and sort them into new subdirectories of those. New directories will be named 0, 1, etc.:

#!/bin/bashmaxfilesperdir=20# loop through all top level directories:while IFS= read -r -d $'\0' topleveldirdo        # enter top level subdirectory:        cd "$topleveldir"        declare -i filecount=0 # number of moved files per dir        declare -i dircount=0  # number of subdirs created per top level dir        # loop through all files in that directory and below        while IFS= read -r -d $'\0' filename        do                # whenever file counter is 0, make a new dir:                if [ "$filecount" -eq 0 ]                then                        mkdir "$dircount"                fi                # move the file into the current dir:                mv "$filename" "${dircount}/"                filecount+=1                # whenever our file counter reaches its maximum, reset it, and                # increase dir counter:                if [ "$filecount" -ge "$maxfilesperdir" ]                then                        dircount+=1                        filecount=0                fi        done < <(find -type f -print0)        # go back to top level:        cd ..done < <(find -mindepth 1 -maxdepth 1 -type d -print0)

The find -print0/read combination with process substitution has been stolen from another question.

It should be noted that simple globbing can handle all kinds of strange directory and file names as well. It is however not easily extensible for multiple levels of directories.