Skip to content

Instantly share code, notes, and snippets.

@storrence88
Last active December 19, 2025 18:00
Show Gist options
  • Select an option

  • Save storrence88/c2e9a67910d6f29e0d88ccda9a7c2720 to your computer and use it in GitHub Desktop.

Select an option

Save storrence88/c2e9a67910d6f29e0d88ccda9a7c2720 to your computer and use it in GitHub Desktop.
#!/bin/bash
# πŸŽ‰ 2025 Shell Wrapped
# A "Spotify Wrapped" style summary of your shell command usage
#
# Usage: curl -sL <gist-raw-url> | bash
# or: chmod +x shell-wrapped-2025.sh && ./shell-wrapped-2025.sh
# ⚠️ SAFETY: This script is 100% read-only. It only reads your shell
# history file and prints statistics. No files are modified or deleted.
# Feel free to audit the code below before running.
set -e
# Detect history file
if [[ -f "$HOME/.zsh_history" ]]; then
HISTORY_FILE="$HOME/.zsh_history"
SHELL_NAME="zsh"
elif [[ -f "$HOME/.bash_history" ]]; then
HISTORY_FILE="$HOME/.bash_history"
SHELL_NAME="bash"
else
echo "Could not find shell history file"
exit 1
fi
# Extract commands (handle zsh extended history format: `: timestamp:0;command`)
extract_commands() {
if [[ "$SHELL_NAME" == "zsh" ]]; then
# Handle zsh extended history format and plain format
sed 's/^: [0-9]*:[0-9]*;//' "$HISTORY_FILE" | sed 's/^[[:space:]]*//'
else
cat "$HISTORY_FILE"
fi
}
# Get first word (the actual command)
get_base_commands() {
extract_commands | awk '{print $1}' | grep -v '^$'
}
# Stats
TOTAL=$(get_base_commands | wc -l | tr -d ' ')
UNIQUE=$(get_base_commands | sort -u | wc -l | tr -d ' ')
# Generate bar (20 chars max)
bar() {
local pct=$1
local filled=$(echo "$pct * 20 / 100" | bc)
local empty=$((20 - filled))
printf '%0.sβ–ˆ' $(seq 1 $filled 2>/dev/null) || true
printf '%0.sβ–‘' $(seq 1 $empty 2>/dev/null) || true
}
# Top commands
top_commands() {
get_base_commands | sort | uniq -c | sort -rn | head -10
}
# Top git subcommands
top_git() {
extract_commands | grep '^git ' | awk '{print $2}' | sort | uniq -c | sort -rn | head -5
}
# Awards
longest_cmd=$(extract_commands | awk '{ print length, $0 }' | sort -rn | head -1 | cut -d' ' -f1)
rm_count=$(extract_commands | grep -c '^rm ' 2>/dev/null || true)
rm_count=${rm_count:-0}
grep_count=$(get_base_commands | grep -cE '^(grep|rg|ag)$' 2>/dev/null || true)
grep_count=${grep_count:-0}
cd_count=$(get_base_commands | grep -c '^cd$' 2>/dev/null || true)
cd_count=${cd_count:-0}
# Max count for percentage calculations
max_count=$(top_commands | head -1 | awk '{print $1}')
# Output
echo ""
echo "╔═══════════════════════════════════════════╗"
echo "β•‘ πŸŽ‰ 2025 SHELL WRAPPED πŸŽ‰ β•‘"
echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"
echo ""
echo " Shell: $SHELL_NAME"
echo " πŸ“Š Total Commands: $(printf "%'d" $TOTAL)"
echo " πŸ”€ Unique Commands: $(printf "%'d" $UNIQUE)"
echo ""
echo "πŸ† TOP 10 COMMANDS"
echo "─────────────────────────────────────────────"
i=1
top_commands | while read count cmd; do
pct=$(echo "scale=1; $count * 100 / $TOTAL" | bc)
pct_bar=$(echo "$count * 100 / $max_count" | bc)
printf " %2d. %-10s $(bar $pct_bar) %'6d (%s%%)\n" $i "$cmd" $count "$pct"
((i++))
done
echo ""
echo "πŸ”§ TOP GIT SUBCOMMANDS"
echo "─────────────────────────────────────────────"
git_max=$(top_git | head -1 | awk '{print $1}')
if [[ -n "$git_max" && "$git_max" -gt 0 ]]; then
i=1
top_git | while read count cmd; do
pct_bar=$(echo "$count * 100 / $git_max" | bc)
printf " %2d. %-10s $(bar $pct_bar) %'6d\n" $i "$cmd" $count
((i++))
done
else
echo " No git commands found"
fi
echo ""
echo "πŸ… AWARDS"
echo "─────────────────────────────────────────────"
echo " πŸ“ Longest Command: $longest_cmd chars"
echo " πŸ—‘οΈ Times you rm'd something: $rm_count"
echo " πŸ” Search commands (grep/rg/ag): $grep_count"
echo " πŸ“‚ Directory changes (cd): $cd_count"
echo ""
echo "─────────────────────────────────────────────"
echo " Generated on $(date '+%Y-%m-%d') | Happy coding! πŸš€"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment