1

I have a folder full of 1000 (or more) files. I want to have a script that creates a numbered folder and then moves the first 20 files (ordered by name) into that folder. It should then do this for the other files, increasing the folder number by 1, until all the files are in folders.

I've tried the following command but it doesn't do a whole directory automatically and doesn't increment the folder number automatically:

N=1000;
for i in ${srcdir}/*; do
  [ $((N--)) = 0 ] && break
  cp -t "${dstdir}" -- "$i"
done

How can this be done using bash?

  • Suggestion: you should try to solve the question, and post your attempt. – ChuckCottrill Oct 18 '13 at 0:52
  • @ChuckCottrill done! Thanks for the suggestion – hellocatfood Oct 19 '13 at 10:07
2

This script takes two (optional) arguments, the directory to partition, and the parition size. Since you didn't say whether you only want to move files, or move everything, I assumed you meant files, so I used the find command.

A few comments,

  • Had you not specified shell, something like this is more easily done in perl, ruby, or python.
  • find with maxdepth 1 does only the directory
  • you can move the files anywhere, just change the folder naming
  • since find is used, you can add -name, -mtime, -ctime, etc.

Copysome.sh,

#!/bin/bash
path=${1:-"."} #directory to start
howmany=${2:-20} #partition size
pushd $path; #move there
part=1; #starting partition
LIST="/usr/bin/find -maxdepth 1 -type f" #move only files?
#LIST="ls" #move everything #be careful, $folder will get moved also :-)
count=`$LIST |/usr/bin/wc -l`; #count of files to move
while [ $count -gt 0 ]; do
    folder="folder-$part";
    if [ ! -d $folder ]; then /usr/bin/mkdir -p $folder; fi
    /usr/bin/mv `$LIST |/usr/bin/sort |/usr/bin/head -$howmany` $folder/.
    count=`$LIST |/usr/bin/wc -l`; #are there more files?
    part=$(expr $part + 1)
done
popd $path

Here is a script to test with (I didn't have an extra 1000 files lying around),

for f in 0 1 2 3 4 5 6 7 8 9; do
  for g in 0 1 2 3 4 5 6 7 8 9; do
    for h in 0 1 2 3 4 5 6 7 8 9; do
        touch $f$g$h
    done
  done
done
0

Only one for loop should be enough when your filesName ending with corresponding numbers but the shell is zsh.

for N in {0..800..20}: do
    mkdir "dir$N"
    mv "files{$N..$((N+19))}" "/path/to/dir$N/"
done

If it's in bash, then:

for N in {0..800..20}: do
    mkdir "dir$N"
    eval mv "files{$N..$((N+19))}" "/path/to/dir$N/"
done

Learning post: How can I use $variable in a shell brace expansion of a sequence?

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.