Created
July 27, 2025 09:01
-
-
Save niskala5570/9288f883bb42c0221c03064760b58b30 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Fancy Tree with emoji, color, depth, size, style and filtering π² | |
# Color codes | |
C_RESET="\033[0m" | |
C_FOLDER="\033[1;34m" | |
C_FILE="\033[0;37m" | |
C_SIZE="\033[0;90m" | |
C_EXEC="\033[1;32m" | |
C_SCRIPT="\033[0;35m" | |
# Tree styles | |
set_tree_style() { | |
case "$1" in | |
ascii) TEE="|--"; ELB="\\--"; PIPE="| "; SPAC=" " ;; | |
dotted) TEE="βββ"; ELB="βββ"; PIPE="β "; SPAC=" " ;; | |
round) TEE="βββ"; ELB="β°ββ"; PIPE="β "; SPAC=" " ;; | |
double) TEE="β ββ"; ELB="βββ"; PIPE="β "; SPAC=" " ;; | |
*) TEE="βββ"; ELB="βββ"; PIPE="β "; SPAC=" " ;; # default | |
esac | |
} | |
# Human-readable file size | |
get_size() { | |
if [ -f "$1" ]; then | |
stat --format="%s" "$1" | awk ' | |
function human(x) { | |
s="B KB MB GB TB PB" | |
split(s, units) | |
while (x>=1024 && i<5) {x/=1024; ++i} | |
return sprintf("%.1f%s", x, units[i+1]) | |
} | |
{print human($1)}' | |
else | |
echo "" | |
fi | |
} | |
# Determine emoji + color | |
get_icon_and_color() { | |
local f="$1" | |
local name="$(basename "$f")" | |
local icon="π" | |
local color="$C_FILE" | |
if [ -d "$f" ]; then icon="π"; color="$C_FOLDER" | |
# Images | |
elif [[ "$name" =~ \.(jpg|jpeg|png|gif|svg)$ ]]; then icon="πΌοΈ" | |
# Video | |
elif [[ "$name" =~ \.(mp4|mkv|mov|avi)$ ]]; then icon="ποΈ" | |
# Audio | |
elif [[ "$name" =~ \.(mp3|wav|flac)$ ]]; then icon="π΅" | |
# Archives | |
elif [[ "$name" =~ \.(zip|tar|gz|rar|7z)$ ]]; then icon="π¦" | |
# Scripts | |
elif [[ "$name" =~ \.(sh|bash)$ ]]; then icon="π"; color="$C_SCRIPT" | |
# Code | |
elif [[ "$name" =~ \.(py|pl|rb|js|ts|cpp|c|hpp|java|rs)$ ]]; then icon="π»"; color="$C_SCRIPT" | |
# Documents | |
elif [[ "$name" =~ \.(pdf|docx?|txt|md)$ ]]; then icon="π" | |
# Subtitles | |
elif [[ "$name" =~ \.(srt|vtt)$ ]]; then icon="π"; color="$C_FILE" | |
elif [[ "$name" =~ \.(ass|ssa)$ ]]; then icon="π¨"; color="$C_SCRIPT" | |
elif [[ "$name" =~ \.(sub|idx)$ ]]; then icon="π§©"; color="$C_FILE" | |
# Executables | |
elif [[ -x "$f" ]]; then icon="βοΈ"; color="$C_EXEC" | |
fi | |
echo "$icon|$color" | |
} | |
# Main recursive printer | |
print_tree() { | |
local dir="$1" | |
local prefix="$2" | |
local depth="$3" | |
[ "$MAX_DEPTH" -ge 0 ] && [ "$depth" -gt "$MAX_DEPTH" ] && return | |
local entries=("$dir"/*) | |
local count=${#entries[@]} | |
for i in "${!entries[@]}"; do | |
local path="${entries[$i]}" | |
[ ! -e "$path" ] && continue | |
local name="$(basename "$path")" | |
# Apply filter | |
if [ -n "$FILTER_EXT" ] && [ -f "$path" ]; then | |
[[ ! "$name" =~ \.$FILTER_EXT$ ]] && continue | |
fi | |
local connector="$TEE" | |
local new_prefix="${prefix}${PIPE}" | |
if [ $((i+1)) -eq "$count" ]; then | |
connector="$ELB" | |
new_prefix="${prefix}${SPAC}" | |
fi | |
IFS="|" read -r icon color <<< "$(get_icon_and_color "$path")" | |
local size="" | |
[ "$SHOW_SIZE" = true ] && size="$(get_size "$path")" | |
[ -n "$size" ] && size=" $C_SIZE[$size]$C_RESET" | |
local line="${prefix}${connector} ${icon} ${color}${name}${C_RESET}${size}" | |
echo -e "$line" | |
[ -n "$OUTPUT_FILE" ] && echo -e "$(echo "$line" | sed 's/\x1B\[[0-9;]*[a-zA-Z]//g')" >> "$OUTPUT_FILE" | |
if [ -d "$path" ]; then | |
print_tree "$path" "$new_prefix" $((depth+1)) | |
fi | |
done | |
} | |
# Default values | |
STYLE="default" | |
TARGET="." | |
SHOW_SIZE=false | |
FILTER_EXT="" | |
MAX_DEPTH=-1 | |
OUTPUT_FILE="" | |
# Parse args | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
--style=*) STYLE="${1#*=}" ;; | |
--depth=*) MAX_DEPTH="${1#*=}" ;; | |
--ext=*) FILTER_EXT="${1#*=}" ;; | |
--size) SHOW_SIZE=true ;; | |
--out=*) OUTPUT_FILE="${1#*=}"; rm -f "$OUTPUT_FILE" ;; | |
-h|--help) | |
echo "Usage: ./fancytree.sh [options] [directory]" | |
echo "Options:" | |
echo " --style=STYLE Tree style (default, ascii, dotted, round, double)" | |
echo " --size Show file sizes" | |
echo " --depth=N Limit depth to N levels" | |
echo " --ext=EXT Filter files by extension (e.g. mp4)" | |
echo " --out=FILE Output plain text to FILE" | |
echo " -h, --help Show this help" | |
exit 0 ;; | |
*) TARGET="$1" ;; | |
esac | |
shift | |
done | |
set_tree_style "$STYLE" | |
echo -e "π $TARGET" | |
[ -n "$OUTPUT_FILE" ] && echo "π $TARGET" > "$OUTPUT_FILE" | |
print_tree "$TARGET" "" 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment