From 5c9a164af68487f25a036d19794e18dcbd9496f8 Mon Sep 17 00:00:00 2001 From: Nathan Wagner Date: Wed, 15 Jul 2015 23:58:06 +0000 Subject: [PATCH] added script to evenly split files --- evensplit | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100755 evensplit diff --git a/evensplit b/evensplit new file mode 100755 index 0000000..65efa8a --- /dev/null +++ b/evensplit @@ -0,0 +1,91 @@ +#!/bin/sh + +# public domain by Nathan Wagner + +# 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] \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 -- 2.40.0