Introduction
LM Studio is an incredible tool for running local LLMs, but because it is typically distributed as an AppImage or manual download, it doesn’t always leave a clean trail. It scatters configuration files, cached blobs, and gigabytes of AI models across your home directory.
In this tutorial, we will use a specialized Bash script to perform a surgical uninstallation, ensuring your Ubuntu system remains lean and clutter-free.
1. Understanding the Uninstallation Logic
Before running a script with sudo privileges, it is vital to understand its “search and destroy” logic. Here is what happens behind the scenes:
- Process Management: The script identifies and terminates any running instances (
lm-studio,lmstudio) to prevent file-locking errors. - XDG Standards: It targets the official Linux directory standards where app data lives:
~/.local/share,~/.config, and~/.cache. - Model Preservation: Because AI models are massive, the script calculates the folder size and asks if you want to keep them for future use or wipe them to reclaim disk space.
- System Scrubbing: If run with root privileges, it cleans up system-wide locations like
/opt,/usr/local/bin, and removes desktop menu shortcuts.
2. How to Use the Uninstaller Script
Step 1: Create the Script
Open your terminal and create a new bash file:
nano uninstall_lm_studio.sh
Paste the script code below into the editor, then save and exit (Ctrl+O, Enter, Ctrl+X).
Step 2: Set Permissions
You must give the system permission to execute the script:
chmod +x uninstall_lm_studio.sh
Step 3: Choose Your Execution Mode
The script supports three different ways to run, depending on your needs:
- The Safety Check (Dry Run): See what would be deleted without actually touching any files.
./uninstall_lm_studio.sh --dry-run - Standard Uninstall: Clean up your current user profile.
./uninstall_lm_studio.sh - System-Wide Wipe: Remove LM Studio for all users and root.
sudo ./uninstall_lm_studio.sh
3. Navigating the Menu Options
| Option | Use Case |
| 1) Specific User | Best if you only want to clean up your own profile. |
| 2) System-wide | Use this if you used sudo to install LM Studio or want it gone from the entire machine. |
| 3) Search and List | Use this if you used sudo to install LM Studio or want it gone from the entire machine. |
| 4) Exit | Closes the script without doing anything. |
4. Manual Verification (Optional)
If you prefer to double-check the work manually, the script focuses on removing these specific directories. If they are gone, your uninstallation was successful:
~/.cache/lm-studio(Temporary files/Shaders)~/.config/LM-Studio(User settings)~/.local/share/lm-studio(Application data)~/.local/share/applications/lm-studio.desktop(Menu icon)
Pro-Tip: If you chose to KEEP your models during uninstallation, you can find them later in
~/.cache/lm-studio/models. This is helpful if you want to move them to an external drive before a final wipe.
Conclusion
By using a structured script instead of manually hunting for files, you ensure that Ubuntu 24.04 stays optimized. Whether you’re troubleshooting a bad install or moving to a different LLM runner, this method is the safest way to ensure a clean slate.
Code:
#!/usr/bin/env bash
# LM Studio Uninstaller for Ubuntu 24.04
# Author: Windows-HQ.com
#
# Usage: sudo ./lm_studio_uninstall.sh [--dry-run]
set -euo pipefail
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m'
# ── Global flags ─────────────────────────────────────────────────────────────
DRY_RUN=false
for arg in "$@"; do [[ "$arg" == "--dry-run" ]] && DRY_RUN=true; done
# ── Temp-file cleanup ─────────────────────────────────────────────────────────
SEARCH_TMP=""
cleanup() { [[ -n "$SEARCH_TMP" && -f "$SEARCH_TMP" ]] && rm -f "$SEARCH_TMP"; }
trap cleanup EXIT
# ── Helpers ───────────────────────────────────────────────────────────────────
banner() {
clear
echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║${NC} ${MAGENTA}LM Studio Uninstaller for Ubuntu 24.04${NC} ${CYAN}║${NC}"
if $DRY_RUN; then
echo -e "${CYAN}║${NC} ${YELLOW}⚠ DRY-RUN MODE — nothing will be deleted${NC} ${CYAN}║${NC}"
fi
echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
}
# Safe remove: honours --dry-run and logs every deletion
safe_rm() {
local path="$1"
if [[ ! -e "$path" && ! -L "$path" ]]; then return 0; fi
if $DRY_RUN; then
echo -e " ${YELLOW}[dry-run]${NC} would remove: $path"
else
echo " Removing: $path"
rm -rf -- "$path"
fi
}
# Confirm with a default-No prompt; returns 0 on yes, 1 on no
confirm() {
local prompt="$1"
local reply
read -r -p " $prompt (y/N): " reply
[[ "${reply,,}" == "y" ]]
}
# Kill processes owned by a user (or any user when called as root)
kill_lm_processes() {
local user="${1:-}"
local patterns=("lm-studio" "LM-Studio" "lmstudio" "LMStudio")
for pat in "${patterns[@]}"; do
if [[ -n "$user" ]]; then
pkill -u "$user" -f "$pat" 2>/dev/null && echo " Killed '$pat' processes for $user" || true
else
pkill -f "$pat" 2>/dev/null && echo " Killed '$pat' processes" || true
fi
done
}
# ── Core: remove all LM Studio artefacts under one home directory ─────────────
#
# Parameters:
# $1 home directory
# $2 username (for display)
# $3 "ask" | "keep" | "remove" — how to handle model directories
#
uninstall_for_user() {
local home_dir="$1"
local username="$2"
local model_policy="${3:-ask}"
local removed=0
echo -e "\n${GREEN}Uninstalling for user: $username${NC}"
# ── XDG dirs: use find -iname so one pass covers every capitalisation ──────
local xdg_roots=("$home_dir/.local/share" "$home_dir/.config" "$home_dir/.cache")
for root in "${xdg_roots[@]}"; do
[[ -d "$root" ]] || continue
while IFS= read -r -d '' path; do
# Skip model dirs — handled separately below
[[ "$path" == */models || "$path" == */models/* ]] && continue
safe_rm "$path"
(( removed++ )) || true
done < <(find "$root" -maxdepth 1 -iname "lm?studio*" -print0 2>/dev/null)
done
# ── Desktop entries ────────────────────────────────────────────────────────
while IFS= read -r -d '' path; do
safe_rm "$path"
(( removed++ )) || true
done < <(find "$home_dir/.local/share/applications" \
-maxdepth 1 -iname "lm?studio*.desktop" -print0 2>/dev/null)
# ── Local binaries ─────────────────────────────────────────────────────────
while IFS= read -r -d '' path; do
safe_rm "$path"
(( removed++ )) || true
done < <(find "$home_dir/.local/bin" \
-maxdepth 1 -iname "lm?studio*" -print0 2>/dev/null)
# ── Model directories ──────────────────────────────────────────────────────
local model_found=""
while IFS= read -r -d '' path; do
[[ -d "$path" ]] && model_found="$path" && break
done < <(find "$home_dir" -maxdepth 5 -type d -iname "models" \
-path "*lm*studio*" -print0 2>/dev/null)
if [[ -n "$model_found" ]]; then
local model_size
model_size=$(du -sh "$model_found" 2>/dev/null | cut -f1)
echo -e "\n ${YELLOW}Found model directory${NC}: $model_found (${model_size})"
local do_remove=false
case "$model_policy" in
remove) do_remove=true ;;
keep) echo " Keeping models (policy=keep)" ;;
ask)
if confirm "Remove downloaded models for $username?"; then
do_remove=true
else
echo " Keeping models"
fi
;;
esac
if $do_remove; then
safe_rm "$(dirname "$model_found")"
(( removed++ )) || true
fi
fi
if (( removed == 0 )); then
echo -e " ${YELLOW}Nothing found for $username${NC}"
else
echo -e " ${GREEN}Done (${removed} item(s) processed)${NC}"
fi
}
# ── Iterate every regular user from /etc/passwd ───────────────────────────────
each_human_user() {
# Callback receives (home, username, extra_args...)
local callback="$1"; shift
while IFS=: read -r username _ uid _ _ home _; do
(( uid >= 1000 && uid < 65534 )) || continue
[[ "$username" == "nobody" ]] && continue
[[ -d "$home" ]] || continue
"$callback" "$home" "$username" "$@"
done < /etc/passwd
}
# ── Option 1: single selected user ───────────────────────────────────────────
uninstall_selected_user() {
echo -e "\n${CYAN}Select a user to uninstall LM Studio${NC}"
echo "────────────────────────────────────────"
local -a users=() homes=()
local i=1
while IFS=: read -r username _ uid _ _ home _; do
(( uid >= 1000 && uid < 65534 )) || continue
[[ "$username" == "nobody" ]] && continue
[[ -d "$home" ]] || continue
users+=("$username"); homes+=("$home")
printf " ${GREEN}%d)${NC} %-20s %s\n" "$i" "$username" "$home"
(( i++ )) || true
done < /etc/passwd
if (( ${#users[@]} == 0 )); then
echo -e "${RED}No regular users found.${NC}"
read -r -p "Press Enter to continue…"; return
fi
local cancel=$i
echo " $cancel) Cancel"
echo
local choice
read -r -p "Choice (1–$cancel): " choice
if ! [[ "$choice" =~ ^[0-9]+$ ]] || (( choice < 1 || choice > cancel )); then
echo -e "${RED}Invalid input.${NC}"
read -r -p "Press Enter to continue…"; return
fi
(( choice == cancel )) && { echo -e "${GREEN}Cancelled.${NC}"; return; }
local idx=$(( choice - 1 ))
echo -e "\n${YELLOW}Uninstalling for: ${users[$idx]}${NC}"
uninstall_for_user "${homes[$idx]}" "${users[$idx]}" ask
kill_lm_processes "${users[$idx]}"
read -r -p $'\nPress Enter to continue…'
}
# ── Option 2: system-wide ─────────────────────────────────────────────────────
uninstall_system_wide() {
echo -e "\n${RED}⚠ SYSTEM-WIDE UNINSTALLATION${NC}"
echo -e "${YELLOW}This removes LM Studio for ALL users, root, and system locations.${NC}"
confirm "Continue?" || { echo -e "${GREEN}Cancelled.${NC}"; return; }
# Ask once about models; apply to every user silently
local model_policy
echo
if confirm "Remove downloaded AI models for all users?"; then
model_policy="remove"
else
model_policy="keep"
fi
echo -e "\n${CYAN}Uninstalling for all regular users…${NC}"
each_human_user uninstall_for_user "$model_policy"
echo -e "\n${CYAN}Uninstalling for root…${NC}"
uninstall_for_user /root root "$model_policy"
echo -e "\n${CYAN}Removing system-wide locations…${NC}"
local sys_roots=(/opt /usr/local /usr/share/applications)
for root in "${sys_roots[@]}"; do
[[ -d "$root" ]] || continue
local depth=1
[[ "$root" == /usr/share/applications ]] && depth=1
while IFS= read -r -d '' path; do
safe_rm "$path"
done < <(find "$root" -maxdepth "$depth" \
\( -iname "lm?studio*" -o -iname "lm-studio*" \) \
-print0 2>/dev/null)
done
echo -e "\n${CYAN}Removing symlinks from PATH locations…${NC}"
for bin_dir in /usr/local/bin /usr/bin; do
[[ -d "$bin_dir" ]] || continue
while IFS= read -r -d '' path; do
safe_rm "$path"
done < <(find "$bin_dir" -maxdepth 1 -type l -iname "lm?studio*" -print0 2>/dev/null)
done
echo -e "\n${CYAN}Stopping running processes…${NC}"
kill_lm_processes ""
command -v update-desktop-database &>/dev/null && update-desktop-database 2>/dev/null || true
echo -e "\n${GREEN}System-wide uninstallation complete.${NC}"
read -r -p $'\nPress Enter to continue…'
}
# ── Option 3: search entire filesystem ───────────────────────────────────────
search_all_files() {
echo -e "\n${CYAN}Scanning filesystem for LM Studio files…${NC}"
echo -e "${YELLOW}This may take several minutes.${NC}\n"
SEARCH_TMP=$(mktemp)
# Directories excluded from the search
local -a prune_paths=(
/proc /sys /dev /run /snap /boot /lost+found /tmp /var/tmp
/var/cache/apt /var/lib/apt /var/lib/dpkg /var/cache/debconf
)
# Build a single find command using -prune for excluded dirs,
# and -iname with -o for all name patterns — NO eval required
local prune_expr=()
for p in "${prune_paths[@]}"; do
prune_expr+=( -path "$p" -o -path "$p/*" -o )
done
# The trailing -o leaves an open OR; close it with a never-true expression
prune_expr+=( -path "/_no_such_path_" )
# Collect all matching paths into the temp file (nullchar-delimited → sorted)
find / \( "${prune_expr[@]}" \) -prune -o \
\( -iname "lm-studio*" -o -iname "lm studio*" -o \
-iname "lmstudio*" -o -iname "LMStudio*" \) -print0 2>/dev/null \
| sort -zu > "$SEARCH_TMP"
# Tally and display
local -a dirs=() files=() links=() other=()
while IFS= read -r -d '' path; do
if [[ -L "$path" ]]; then links+=("$path")
elif [[ -d "$path" ]]; then dirs+=("$path")
elif [[ -f "$path" ]]; then files+=("$path")
else other+=("$path")
fi
done < "$SEARCH_TMP"
local total=$(( ${#dirs[@]} + ${#files[@]} + ${#links[@]} + ${#other[@]} ))
echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}"
echo -e "${MAGENTA}Directories (${#dirs[@]}):${NC}"
for p in "${dirs[@]}"; do printf " %s\n" "$p"; done
[[ ${#dirs[@]} -eq 0 ]] && echo " (none)"
echo -e "\n${MAGENTA}Files (${#files[@]}):${NC}"
for p in "${files[@]}"; do
local sz; sz=$(du -sh "$p" 2>/dev/null | cut -f1)
printf " %-60s %s\n" "$p" "$sz"
done
[[ ${#files[@]} -eq 0 ]] && echo " (none)"
echo -e "\n${MAGENTA}Symlinks (${#links[@]}):${NC}"
for p in "${links[@]}"; do printf " %s -> %s\n" "$p" "$(readlink "$p")"; done
[[ ${#links[@]} -eq 0 ]] && echo " (none)"
echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN}Total: $total item(s) found " \
"(dirs: ${#dirs[@]}, files: ${#files[@]}, symlinks: ${#links[@]})${NC}"
echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}"
if confirm "Save these results to a file?"; then
local out="lm_studio_search_$(date +%Y%m%d_%H%M%S).txt"
{
echo "LM Studio file search — $(date)"
echo "DIRECTORIES:"; printf " %s\n" "${dirs[@]:-}"
echo "FILES:"; printf " %s\n" "${files[@]:-}"
echo "SYMLINKS:"; printf " %s -> %s\n" "${links[@]:-}"
echo "Total: $total"
} > "$out"
echo -e "${GREEN}Saved to: $out${NC}"
fi
if (( total > 0 )); then
echo
if confirm "Remove all found LM Studio items?"; then
echo -e "${YELLOW}Removing…${NC}"
local fail=0
# Process deepest paths first so parent dirs aren't removed before children
readarray -td '' sorted_paths < <(printf '%s\0' \
"${dirs[@]:-}" "${files[@]:-}" "${links[@]:-}" "${other[@]:-}" \
| sort -rzu)
for path in "${sorted_paths[@]}"; do
safe_rm "$path" || (( fail++ )) || true
done
(( fail > 0 )) && echo -e "${YELLOW}${fail} item(s) could not be removed.${NC}"
echo -e "${GREEN}Done.${NC}"
fi
fi
read -r -p $'\nPress Enter to continue…'
}
# ── Main menu ─────────────────────────────────────────────────────────────────
while true; do
banner
echo -e "${CYAN}Select an option:${NC}\n"
echo -e " ${GREEN}1)${NC} Uninstall for a specific user"
echo -e " ${GREEN}2)${NC} Uninstall system-wide (all users + root) ${RED}[requires sudo]${NC}"
echo -e " ${GREEN}3)${NC} Search and list all LM Studio files"
echo -e " ${RED}4)${NC} Exit"
echo
read -r -p "Choice (1–4): " choice
case "${choice// /}" in
1) uninstall_selected_user ;;
2)
if (( EUID != 0 )); then
echo -e "\n${RED}System-wide uninstallation requires root.${NC}"
echo -e "${YELLOW}Re-run with: sudo $0${NC}"
read -r -p $'\nPress Enter to continue…'
else
uninstall_system_wide
fi
;;
3)
(( EUID != 0 )) && \
echo -e "\n${YELLOW}Running without sudo — some directories may be inaccessible.${NC}\n"
search_all_files
;;
4) echo -e "\n${GREEN}Goodbye.${NC}"; exit 0 ;;
*) echo -e "\n${RED}Invalid choice.${NC}"; sleep 1 ;;
esac
done