!/usr/bin/env bash
Recursive tree with Unicode branches, directories first, then files
Shows file sizes and total files per directory
print_tree() {
local dir="$1"
local prefix="$2"
local maxdepth="${3:-0}" # 0 = unlimited
local depth="${4:-1}"
# Check maxdepth
if [[ $maxdepth -ne 0 && $depth -gt $maxdepth ]]; then
return
fi
# Get sorted directories and files
local entries=("$dir"/*)
local dirs=()
local files=()
for e in "${entries[@]}"; do
[[ -d "$e" ]] && dirs+=("$e")
[[ -f "$e" ]] && files+=("$e")
done
# Process directories first
local count=${#dirs[@]}
for i in "${!dirs[@]}"; do
local d="${dirs[i]}"
local branch="├──"
[[ $i -eq $((count-1)) ]] && branch="└──"
echo "${prefix}${branch} ${d##*/}"
# Recurse into subdirectory
local new_prefix="$prefix"
[[ $i -eq $((count-1)) ]] && new_prefix+=" " || new_prefix+="│ "
print_tree "$d" "$new_prefix" "$maxdepth" $((depth+1))
done
# Then files
count=${#files[@]}
local file_count=0
for i in "${!files[@]}"; do
local f="${files[i]}"
local branch="├──"
[[ $i -eq $((count-1)) ]] && branch="└──"
# get human-readable size
local size
if command -v stat >/dev/null 2>&1; then
# Linux/macOS compatible
size=$(stat -c "%s" "$f" 2>/dev/null || stat -f "%z" "$f")
else
size="?"
fi
# convert size to human-readable
local hr_size
if [[ "$size" =~ ^[0-9]+$ ]]; then
if [ "$size" -lt 1024 ]; then
hr_size="${size}B"
elif [ "$size" -lt $((1024*1024)) ]; then
hr_size="$((size/1024))K"
elif [ "$size" -lt $((1024*1024*1024)) ]; then
hr_size="$((size/1024/1024))M"
else
hr_size="$((size/1024/1024/1024))G"
fi
else
hr_size="?"
fi
echo "${prefix}${branch} ${f##*/} [${hr_size}]"
((file_count++))
done
# Print total files count in this directory
if [ $file_count -gt 0 ]; then
echo "${prefix}└── Total files: $file_count"
fi
}
Usage:
print_tree
Example: print_tree . "" 0 # unlimited depth
print_tree . "" 0
Top comments (0)