File: filesizes.sh
   1 #!/bin/sh
   2 
   3 # The MIT License (MIT)
   4 #
   5 # Copyright (c) 2026 pacman64
   6 #
   7 # Permission is hereby granted, free of charge, to any person obtaining a copy
   8 # of this software and associated documentation files (the "Software"), to deal
   9 # in the Software without restriction, including without limitation the rights
  10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 # copies of the Software, and to permit persons to whom the Software is
  12 # furnished to do so, subject to the following conditions:
  13 #
  14 # The above copyright notice and this permission notice shall be included in
  15 # all copies or substantial portions of the Software.
  16 #
  17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23 # SOFTWARE.
  24 
  25 
  26 # filesizes [options...] [files/folders...]
  27 #
  28 #
  29 # Show all filesizes as TSV lines, after a header/column line. Besides sizes
  30 # in bytes, the size in 1024-byte kilobytes is also shown, rounded up. By
  31 # default the block-size used to round up is 4, which amounts to 4096-byte
  32 # blocks.
  33 #
  34 # You can change the block-size round-up via the likes of `-4k`, `-8k`, and
  35 # so on, without the quotes. Also, you can give this tool a mix of files and
  36 # folders, allowing you to run it with expanding file-patterns on the shell.
  37 #
  38 # The options are, available both in single and double-dash versions
  39 #
  40 #   -4k, -8k, -16k, ...    custom block-size round-up
  41 #   -h, -help              show this help message
  42 #   -s, -sort, -sorted     reverse-sort by filesize
  43 #   -t, -top               limit search to top-level files, in folders given
  44 
  45 
  46 sorted=0
  47 max_depth=''
  48 block_size=4
  49 
  50 while [ $# -gt 0 ]; do
  51     case "$1" in
  52         -h|--h|-help|--help)
  53             awk '/^# +filesizes /, /^$/ { gsub(/^# ?/, ""); print }' "$0"
  54             exit 0
  55         ;;
  56 
  57         -s|--s|-sort|--sort|-sorted|--sorted)
  58             sorted=1; shift; continue
  59         ;;
  60 
  61         -t|--t|-top|--top)
  62             max_depth='-maxdepth 1'; shift; continue
  63         ;;
  64 
  65         --) break ;;
  66     esac
  67 
  68     break
  69 done
  70 
  71 if [ $# -eq 0 ]; then
  72     awk '/^# +filesizes /, /^$/ { gsub(/^# ?/, ""); print }' "$0"
  73     exit 0
  74 fi
  75 
  76 if echo "$1" | grep -E -q '^--?[0-9][kK]+$'; then
  77     block_size="$(echo "$1" | sed 's-[^0-9]--g')"
  78     shift
  79 elif echo "$1" | grep -E -q '^-[^-]'; then
  80     printf "unsupported option '%s'\n" "$1" >&2
  81     exit 1
  82 fi
  83 
  84 [ "$1" = '--' ] && shift
  85 
  86 printf "file\tbytes\tblocks\n"
  87 
  88 for arg in "${@:-.}"; do
  89     if [ -f "${arg}" ]; then
  90         wc -c "${arg}"
  91         continue
  92     fi
  93 
  94     if [ -d "${arg}" ]; then
  95         find "${arg}" ${max_depth} -type f -exec wc -c {} +
  96     fi
  97 done | awk '
  98     {
  99         gsub(/^ *| *\r$/, "")
 100         gsub(/^([^ ])*/, "&\t")
 101         gsub(/ *\t */, "\t")
 102         print
 103     }
 104 ' | awk -F "\t" -v OFS="\t" -v block="${block_size}" '
 105     function emit(name, size, f, n) {
 106         f = size / (block * 1024)
 107         n = f - f % 1
 108         if (f % 1) n++
 109         print name, size, n * block
 110     }
 111 
 112     NR > 1 { emit(name, size) }
 113     { name = $2; size = $1 }
 114     END { if (NR == 1) emit(name, size) }
 115 ' | if [ "${sorted}" -eq 1 ]; then
 116     sort -t "$(printf '\t')" -k2,2rn -k1,1
 117 else
 118     cat
 119 fi