This all started with a simple alias:

alias sizes="du -sh * | sort -n"

That outputs all of the file and folder sizes in the current directory, sorted by size, and lists them in human-readable format. Of course, I wanted to make it a more painful endeavor.

Here’s the result. It’s a shell function that will output the file sizes for files (not folders) and provide a total. It accepts file extensions as arguments, and there are flags for controlling sort order and directory traversal depth. Given the lack of real utility, I won’t go into too much depth, other than to say that the __sizeup_build_query and __sizeup_humanize functions are reusable and pretty handy.

To run in the current folder, just use sizeup. Additional options are:

-r	reverse sort
-[0-3]	limit depth (default 4 levels, 0=unlimited)

arguments limit by file extension

Here’s the code that can be added to or sourced by your .*_profile setup.

__sizeup_build_query () {
	local bool="and"
	local query=""
	for t in $@; do
		query="$query -$bool -iname \"*.$t\""
	echo -n "$query"

__sizeup_humanize () {
	local size=$1
	if [ $size -ge 1073741824 ]; then
		printf '%6.2f%s' $(echo "scale=2;$size/1073741824"| bc) G
	elif [ $size -ge 1048576 ]; then
		printf '%6.2f%s' $(echo "scale=2;$size/1048576"| bc) M
	elif [ $size -ge 1024 ]; then
		printf '%6.2f%s' $(echo "scale=2;$size/1024"| bc) K
		printf '%6.2f%s' ${size} b

sizeup () {
	local helpstring="Show file sizes for all files with totals\n-r\treverse sort\n-[0-3]\tlimit depth (default 4 levels, 0=unlimited)\nAdditional arguments limit by file extension\n\nUsage: sizeup [-r[0123]] ext [,ext]"
	local totalb=0
	local size output reverse OPT
	local depth="-maxdepth 4"
	while getopts "hr0123" opt; do
		case $opt in
			r) reverse="-r " ;;
			0) depth="" ;;
			1) depth="-maxdepth 1" ;;
			2) depth="-maxdepth 2" ;;
			3) depth="-maxdepth 3" ;;
			h) echo -e $helpstring; return;;
			\?) echo "Invalid option: -$OPTARG" >&2; return 1;;
	shift $((OPTIND-1))

	local cmd="find . -type f ${depth}$(__sizeup_build_query $@)"
	local counter=0
	while read -r file; do
		counter=$(( $counter+1 ))
		size=$(stat -f '%z' "$file")
		totalb=$(( $totalb+$size ))
		>&2 echo -ne $'\E[K\e[1;32m'"${counter}:"$'\e[1;31m'" $file "$'\e[0m'"("$'\e[1;31m'$size$'\e[0m'")"$'\r'
		# >&2 echo -n "$(__sizeup_humanize $totalb): $file ($size)"
		# >&2 echo -n $'\r'
		output="${output}${file#*/}*$size*$(__sizeup_humanize $size)\n"
	done < <(eval $cmd)
	>&2 echo -ne $'\r\E[K\e[0m'
	echo -e "$output"| sort -t '*' ${reverse}-nk 2 | cut -d '*' -f 1,3 | column -s '*' -t
	echo $'\e[1;33;40m'"Total: "$'\e[1;32;40m'"$(__sizeup_humanize $totalb)"$'\e[1;33;40m'" in $counter files"$'\e[0m'

Ryan Irelan has produced a series of shell trick videos based on posts. Readers can get 10% off using the coupon code TERPSTRA.