]> pd.if.org Git - scripts/commitdiff
added script to evenly split files
authorNathan Wagner <nw@hydaspes.if.org>
Wed, 15 Jul 2015 23:58:06 +0000 (23:58 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Wed, 15 Jul 2015 23:58:06 +0000 (23:58 +0000)
evensplit [new file with mode: 0755]

diff --git a/evensplit b/evensplit
new file mode 100755 (executable)
index 0000000..65efa8a
--- /dev/null
+++ b/evensplit
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+# public domain by Nathan Wagner <nw@hydaspes.if.org>
+
+# Assume N bytes total.
+# Assume L is the lowest number of files allowable.
+# H is the highest number of files allowable.
+# F is the actual number of files used
+# B is the minimum bytes per file
+# R is the remaining bytes if all files are of size B
+# K is the maximum number of files allowed to be one byte larger than the
+# minimum, K < F
+# 
+# So, you need to determine if there is some L <= F <= H such that R <= K.
+# 
+# For a given candidate F:
+# B = floor(N / F)
+# R = N % B
+# if R <= K then the candidate F is allowable, F files will be used,
+# R of them will be of size B+1 and F-R of them will be of size B.
+
+N=
+L=
+H=
+K=
+ECHO=
+VERBOSE=0
+
+set -e
+
+while getopts l:h:k:n:ev flag ; do
+       case $flag in
+               l) L="$OPTARG" ;;
+               h) H="$OPTARG" ;;
+               k) K="$OPTARG" ;;
+               n) N="$OPTARG" ;;
+               e) ECHO=echo ;;
+               v) VERBOSE=1 ;;
+               ?) printf "Usage: evensplit [-lhknev] <file>\n" 1>&2; exit 2 ;;
+       esac
+done
+shift $(($OPTIND - 1))
+
+INPUT=$1
+
+N=$(stat -c '%s' $INPUT)
+: ${L:=$((N/65536))} # default to at least 65536 bytes per split
+if [ $L -lt 1 ]; then L=1; fi
+
+: ${H:=$N} # use one byte per file if needed
+if [ $H -lt $L ]; then H=$L; fi
+
+: ${K:=$((H-1))} # by default K can by any number of the files
+
+status=1
+
+if [ $VERBOSE -ne 0 ]; then
+       echo '#' F files: $L '<= F <=' $H, at most $K files one byte larger 1>&2
+fi
+
+for F in $(seq $L $H); do
+       B=$(($N / $F))
+       R=$(($N % $B))
+       if [ $R -le $K ]; then
+               if [ $VERBOSE -ne 0 ]; then
+                       printf "# Usable: %u files, size %u" $((F-R)) $B 1>&2
+                       if [ $R -gt 0 ]; then
+                               printf ", %u size %u", $R $((B+1)) 1>&2
+                       fi
+                       printf "\n" 1>&2
+               fi
+               status=0;
+               break;
+       fi
+done
+if [ $? -ne 0 ]; then
+       echo "no usable splits found" 1>&2;
+       exit $status
+fi
+
+DD="dd if=$INPUT count=1"
+
+# ok, at this point we want F-R files of size $B
+for ext in $(seq -w 1 $F); do
+       x=$(echo $ext | sed -e 's/^0\+//')
+       if [ $x -gt $((F-R)) ]; then
+       ${ECHO} $DD of=${INPUT}.$ext bs=$((B+1)) skip=$(((F-R) * B)) iflag=skip_bytes
+       else
+       ${ECHO} $DD of=${INPUT}.$ext bs=$B skip=$((x-1))
+       fi
+done