[Racket] Split current directory to smaller chunks

Sometimes you want to split a big directory into smaller parts.

This is what my util does:

 % ls
change.txt    ft_sql.txt    indent.txt        pi_logipat.txt  rileft.txt    undo.txt    usr_20.txt  usr_40.txt    version8.txt
channel.txt   gui.txt       index.txt         pi_netrw.txt    scroll.txt    usr_01.txt  usr_21.txt  usr_41.txt    vi_diff.txt
cmdline.txt   gui_w32.txt   insert.txt        pi_paren.txt    sign.txt      usr_02.txt  usr_22.txt  usr_42.txt    vim.1
debugger.txt  gui_x11.txt   intro.txt         pi_spec.txt     spell.txt     usr_03.txt  usr_23.txt  usr_43.txt    vim.man
develop.txt   helphelp.txt  tmp               pi_tar.txt      starting.txt  usr_04.txt  usr_24.txt  usr_44.txt    visual.txt
diff.txt      if_cscop.txt  map.txt           pi_vimball.txt  syntax.txt    usr_05.txt  usr_25.txt  usr_45.txt    windows.txt
digraph.txt   if_lua.txt    mbyte.txt         popup.txt       tabpage.txt   usr_06.txt  usr_26.txt  usr_90.txt    workshop.txt
editing.txt   if_mzsch.txt  message.txt       print.txt       tagsrch.txt   usr_07.txt  usr_27.txt  usr_toc.txt   xxd.1
eval.txt      if_ole.txt    motion.txt        quickfix.txt    terminal.txt  usr_08.txt  usr_28.txt  various.txt   xxd.man
filetype.txt  if_perl.txt   netbeans.txt      quickref.txt    term.txt      usr_09.txt  usr_29.txt  version4.txt
fold.txt      if_pyth.txt   options.txt       recover.txt     testing.txt   usr_10.txt  usr_30.txt  version5.txt
ft_ada.txt    if_ruby.txt   pattern.txt       remote.txt      textprop.txt  usr_11.txt  usr_31.txt  version6.txt
ft_rust.txt   if_tcl.txt    pi_getscript.txt  repeat.txt      tips.txt      usr_12.txt  usr_32.txt  version7.txt

 % racket /home/i/tmp/split_dir.rkt 10 *

 % ls
part_0  part_1  part_10  part_11  part_2  part_3  part_4  part_5  part_6  part_7  part_8  part_9

 % ls -R
.:
part_0  part_1  part_10  part_11  part_2  part_3  part_4  part_5  part_6  part_7  part_8  part_9

./part_0:
change.txt  channel.txt  cmdline.txt  debugger.txt  develop.txt  diff.txt  digraph.txt  editing.txt  eval.txt  filetype.txt

./part_1:
fold.txt  ft_ada.txt  ft_rust.txt  ft_sql.txt  gui.txt  gui_w32.txt  gui_x11.txt  helphelp.txt  if_cscop.txt  if_lua.txt

./part_10:
version4.txt  version5.txt  version6.txt  version7.txt  version8.txt  vi_diff.txt  vim.1  vim.man  visual.txt  windows.txt

...

./part_7:
usr_05.txt  usr_06.txt  usr_07.txt  usr_08.txt  usr_09.txt  usr_10.txt  usr_11.txt  usr_12.txt  usr_20.txt  usr_21.txt

./part_8:
usr_22.txt  usr_23.txt  usr_24.txt  usr_25.txt  usr_26.txt  usr_27.txt  usr_28.txt  usr_29.txt  usr_30.txt  usr_31.txt

./part_9:
usr_32.txt  usr_40.txt  usr_41.txt  usr_42.txt  usr_43.txt  usr_44.txt  usr_45.txt  usr_90.txt  usr_toc.txt  various.txt

Racket code:

#lang racket

; https://stackoverflow.com/questions/8725832/how-to-split-list-into-evenly-sized-chunks-in-racket-scheme/25150437#25150437
(define (group n xs)
  (let loop ([grouped '()] [xs xs])
    (cond
      [(empty? xs)
       (reverse grouped)]
      [(<= (length xs) n)
       (loop (cons xs grouped) '())]
      [else (loop (cons (take xs n) grouped)
                  (drop xs n))])))

(define cmd (vector->list (current-command-line-arguments)))

(when (< (length cmd) 2)
  (displayln "usage: racket split_dir.rkt <size> <filemask (glob)>")
  (displayln "for example: racket split_cur_dir.rkt 10 *.jpg")
  (exit))

(define files '())

(define part-size (string->number (first cmd)))

(for ([p (rest cmd)])
  (let-values ([(p-path p-filename p-something) (split-path p)])
    (set! files (cons (path->string p-filename) files))))

(when (eq? (length files) 0)
  (displayln "Error: no files in current dir")
  (exit))

(when (<= (length files) part-size)
  (displayln (string-append "Error: files count (" (~v (length files)) ") < part-size (" (~v part-size) "). not enough to be processed."))
  (exit))

(define tmp (group part-size (sort files string<?)))

(define (mkdir dir)
  (unless (directory-exists? dir)
    (make-directory dir)))

(for ([t tmp]
      [i (range (length tmp))])
  (define out_path (string-append "part_" (~v i) "/"))
  (mkdir out_path)
  (for ([file t])
    (rename-file-or-directory file (string-append out_path file))))

It can "relocate" both files and directories. First argument in command-line is a number of files in each "part_" directory.

Download it.

Further work: use in-slice.


List of my other blog posts.

Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.