#!/bin/bash function helpexit() { echo "Display file/folder sizes like 'du', but faster and actual byte sizes" echo "Returns only the size as number" echo " -h Human readable units" echo " -s Summary mode, otherwise each argument folder calculated separate" echo " -c Count files in addition of summarizing sizes" echo " -a Display animation while counting" echo " -f # Format filesize to human readable. Command exits without scanning." echo " --help This help" exit } function filesize() { # Return a human readable size from integer of bytes # Usage: filesize 10000 [ "$1" = "0" ] && { echo "0~B" return 0 } awk 'BEGIN{ x = '$1' split("B kB MB GB TB PB EB ZB", type) for(i=7;y < 1;i--) y = x / (2^(10*i)) if (i==-1) { printf( "%d~B", x) } if (i>-1) { printf( "%0.1f%s", y, type[i+2]) } }' || return $? } function siprefix() { # Return a SI prefixed string from integer [ "$1" = "0" ] && { echo "0~#" return 0 } awk 'BEGIN{ x = '$1' split("# k# M# G# T# P# E# Z#",type) for(i=7;y < 1;i--) y = x / (10^(3*i)) if (i==-1) { printf( "%d~#", x) } if (i>-1) { printf( "%0.1f%s", y, type[i+2]) } }' || return $? } function animate() { CHARS=( "| " "/ " " _ " " \\" " |" " \\" " _ " "/ " ) i=0 while true; do sleep 0.2 printf "\r %s\r" "${CHARS[$i]}" >&2 i=$(( (i + 1)%${#CHARS[@]} )) done } function processfolder() { if [[ "$ANIMATE" -eq 1 ]]; then SIZECOUNT=( $( \ find "$@" -type f -printf %s"\n" 2>/dev/null | \ awk '{ sum += $1; count += 1; printf " %dMb/%d#\r", sum/(1024*1024), count > "/dev/stderr" } END { printf("%0.f %0.f",sum+0, count+0)}' \ ) ) echo -e -n "\033[K" >&2 else SIZECOUNT=( $( find "$@" -type f -printf %s"\n" 2>/dev/null | awk '{ sum += $1; count += 1 } END { printf("%0.f %0.f",sum+0, count+0)}' ) ) fi SIZE=${SIZECOUNT[0]} [[ "$HUMAN" -eq 1 ]] && { SIZE=$( filesize "$SIZE" ) } [[ "$COUNT" -eq 1 ]] && { COUNTS=${SIZECOUNT[1]} [[ "$HUMAN" -eq 1 ]] && { COUNTS=$( siprefix "$COUNTS" ) } } echo -e "$SIZE\t$COUNTS" } function formatter() { cat - | xargs printf "$FORMAT" | sed -e 's,~B, B,' -e 's,~#, #,' } # Get options what=() for (( i=1; i<=$#; i++ )); do [[ "${!i}" = "-f" ]] && { FORMAT=1; ((i++)); FORMAT_VALUE=${!i}; continue; } [[ "${!i}" = "--help" ]] && helpexit [[ "${!i}" = "-"* ]] && { [[ "${!i}" =~ -.*a ]] && { ANIMATE=1; } [[ "${!i}" =~ -.*h ]] && { HUMAN=1; } [[ "${!i}" =~ -.*c ]] && { COUNT=1; } [[ "${!i}" =~ -.*s ]] && { SUMMARY=1; } continue } what+=( "${!i}" ) done [[ -z "${what[@]}" ]] && what="." # If formatting requested, do only that: if [[ "$FORMAT" -eq 1 ]]; then if [[ -z "$FORMAT_VALUE" ]]; then echo -e "\nBytes argument missing\n\n" helpexit fi filesize $FORMAT_VALUE | sed 's,~B, B,' exit $? fi # If only one entry, dont print the name [[ "${#what[@]}" -eq 1 ]] && SUMMARY=1 if [[ "$ANIMATE" -eq 1 ]]; then trap 'trap - SIGTERM && kill -- -$$' EXIT SIGINT SIGTERM animate & fi [[ "$HUMAN" -eq 1 ]] && NUMFORMAT="%7s " [[ "$HUMAN" -ne 1 ]] && NUMFORMAT="%d\t" [[ "$COUNT" -eq 1 ]] && NUMBERS="$NUMFORMAT$NUMFORMAT" [[ "$COUNT" -ne 1 ]] && NUMBERS="$NUMFORMAT" [[ "SUMMARY" -eq 1 ]] && FORMAT="$NUMBERS\n" [[ "SUMMARY" -ne 1 ]] && FORMAT="$NUMBERS" if [[ "$SUMMARY" -eq 1 ]]; then # Display one line processfolder "${what[@]}" | formatter else # One size for each argument for ((i=0; i<"${#what[@]}"; i++)); do processfolder "${what[$i]}" | formatter echo "${what[$i]}" done fi if [[ "$ANIMATE" -eq 1 ]]; then trap - EXIT SIGINT SIGTERM kill %1 fi