Skip to main content

Outputs a directory listing in a friendly and useful format.

#!/usr/bin/env bash

#
# formatdir -- Outputs a directory listing in a friendly and useful format.
#
# Usage:
#
#   format-dir.sh <path/to/dir/>
#   LICENSE.md (4Kb)                         README.md (8Kb)
#   appveyor.yml (4Kb)                       docs (7 entries)
#   global.json (4Kb)                        nuget.exe (3.77Mb)
#   package.json (4Kb)                       src (10 entries)
#   webpack.config.js (4Kb)                  yarn.lock (108Kb)
#
# from no starch press Wicked Cool Shell Scripts, 2nd Edition
#

#
# scriptbc--Wrapper for 'bc' that returns the result of a calculation
scriptbc()
{
  if [ "$1" = "-p" ] ; then
    precision=$2
    shift 2
  else
    precision=2  # default
  fi

bc -q << EOF
scale=$precision
$*
quit
EOF
}

# Function to format sizes in Kb to Kb, Mb, or Gb for more readable output.
readablesize()
{
  if [ $1 -ge 1048576 ] ; then
    echo "$(scriptbc -p 2 $1 / 1048576)Gb"
  elif [ $1 -ge 1024 ] ; then
    echo  "$(scriptbc -p 2 $1 / 1024)Mb"
  else
    echo "${1}Kb"
  fi
}

#################
## MAIN CODE

if [ $# -gt 1 ] ; then
  echo "Usage: $0 [dirname]" >&2; exit 1
elif [ $# -eq 1 ] ; then   # Specified a directory other than the current one?
  cd "$@"                  # Then let's change to that one.
  if [ $? -ne 0 ] ; then   # Or quit if the directory doesn't exist
    exit 1
  fi
fi

for file in *
do
  if [ -d "$file" ] ; then
    size=$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')
    if [ $size -eq 1 ] ; then
      echo "$file ($size entry)|"
    else
      echo "$file ($size entries)|"
    fi
  else
    size="$(ls -sk "$file" | awk '{print $1}')"
    echo "$file ($(readablesize $size))|"
  fi
done | \
  sed 's/ /^^^/g'  | \
  xargs -n 2     | \
  sed 's/\^\^\^/ /g' | \
  awk -F\| '{ printf "%-39s %-39s\n", $1, $2 }'

exit 0