Created
September 11, 2025 13:06
-
-
Save mevanlc/6ba1f76c69e9e73d80343ba426c67680 to your computer and use it in GitHub Desktop.
uninstall bitdefender
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 | |
| # uninstall_bitdefender.sh | |
| # Purpose: Remove Bitdefender Antivirus for Mac files as outlined in the vendor PDF. | |
| # Works in Recovery mode (preferred when Finder removal fails) and can also run in normal macOS. | |
| # Usage: | |
| # 1) Recovery mode (recommended if Finder method failed): | |
| # chmod +x uninstall_bitdefender.sh | |
| # ./uninstall_bitdefender.sh --volume "Macintosh HD" | |
| # 2) Normal mode (may fail due to protections, but safe to try): | |
| # sudo ./uninstall_bitdefender.sh | |
| # Flags: | |
| # --volume NAME Specify the startup disk under /Volumes (ex: "Macintosh HD"). | |
| # --dry-run Show what would be removed without deleting anything. | |
| # --force Do not prompt for confirmation. | |
| # | |
| # Notes from the PDF: | |
| # - Recovery Terminal method removes SelfProtect.kext and the /Library/Bitdefender folder. | |
| # - Finder method also removes Application Support items and additional kexts when present. | |
| # | |
| set -o errexit | |
| set -o nounset | |
| set -o pipefail | |
| IFS=$'\n\t' | |
| info() { printf "[INFO] %s\n" "$*"; } | |
| warn() { printf "[WARN] %s\n" "$*" >&2; } | |
| error() { printf "[ERROR] %s\n" "$*" >&2; exit 1; } | |
| # Default options | |
| DRY_RUN=0 | |
| FORCE=0 | |
| VOLUME_NAME="" | |
| # Parse args | |
| while (( "$#" )); do | |
| case "$1" in | |
| --dry-run) DRY_RUN=1; shift ;; | |
| --force) FORCE=1; shift ;; | |
| --volume) shift; VOLUME_NAME="${1:-}"; [[ -z "$VOLUME_NAME" ]] && error "--volume requires a name"; shift ;; | |
| *) error "Unknown argument: $1" ;; | |
| esac | |
| done | |
| # Root check (not strictly required in Recovery, but good practice) | |
| if [[ "$(id -u)" -ne 0 ]]; then | |
| warn "Not running as root. Re-running with sudo..." | |
| exec sudo -- "$(command -v bash)" "$0" ${VOLUME_NAME:+--volume "$VOLUME_NAME"} $([[ $DRY_RUN -eq 1 ]] && printf -- "--dry-run ") $([[ $FORCE -eq 1 ]] && printf -- "--force ") | |
| fi | |
| # Determine base path of the target system volume. | |
| BASE="/" | |
| detect_base() { | |
| # If we can see BD artifacts on /, use root. | |
| if [[ -e "/Library/Extensions/SelfProtect.kext" || -e "/Library/Bitdefender" || -e "/Library/Application Support/Bitdefender" ]]; then | |
| BASE="/" | |
| return | |
| fi | |
| # If a specific volume was provided, validate it exists. | |
| if [[ -n "$VOLUME_NAME" ]]; then | |
| local vol_path="/Volumes/$VOLUME_NAME" | |
| [[ -d "$vol_path" ]] || error "Volume not found: $vol_path" | |
| BASE="$vol_path" | |
| return | |
| fi | |
| # Try common default. | |
| if [[ -d "/Volumes/Macintosh HD" ]]; then | |
| BASE="/Volumes/Macintosh HD" | |
| return | |
| fi | |
| # Otherwise, try to auto-pick a plausible system volume. | |
| local candidates=() | |
| for d in /Volumes/*; do | |
| [[ -d "$d" ]] || continue | |
| if [[ -e "$d/System/Library/CoreServices/SystemVersion.plist" && -d "$d/Library" ]]; then | |
| candidates+=("$d") | |
| fi | |
| done | |
| if [[ "${#candidates[@]}" -eq 1 ]]; then | |
| BASE="${candidates[0]}" | |
| else | |
| warn "Could not unambiguously detect the system volume." | |
| warn "Found candidates:" | |
| for c in "${candidates[@]}"; do printf " - %s\n" "$c"; done | |
| error "Re-run with: --volume \"Your Startup Disk Name\"" | |
| fi | |
| } | |
| detect_base | |
| info "Using system volume base: $BASE" | |
| # Safety: refuse to operate if BASE looks wrong. | |
| [[ "$BASE" == "/" || "$BASE" == /Volumes/* ]] || error "Invalid BASE path: $BASE" | |
| # Construct list of targets, from most critical (per PDF method 2) to optional (per method 1). | |
| declare -a TARGETS=( | |
| # Method 2 core targets | |
| "$BASE/Library/Extensions/SelfProtect.kext" | |
| "$BASE/Library/Bitdefender" | |
| # Method 1 additional targets (best effort) | |
| "$BASE/Library/Extensions/FileProtect.kext" | |
| "$BASE/Library/Extensions/TMProtection.kext" | |
| "$BASE/Library/Application Support/Antivirus for Mac" | |
| "$BASE/Library/Application Support/Bitdefender" | |
| "$BASE/Applications/Antivirus for Mac.app" | |
| "$BASE/Applications/Bitdefender.app" | |
| "$BASE/Applications/Bitdefender" | |
| ) | |
| # Safety checks for rm -rf | |
| safe_rm() { | |
| local path="$1" | |
| # Must not be empty | |
| [[ -n "$path" ]] || error "Refusing to delete an empty path" | |
| # Only allow under BASE/Library or BASE/Applications | |
| case "$path" in | |
| "$BASE/Library/"|"$BASE/Applications/") error "Refusing to delete top-level Library/Applications";; | |
| "$BASE/Library/"*|"$BASE/Applications/"*) ;; | |
| *) error "Refusing to delete path outside $BASE/Library or $BASE/Applications: $path" ;; | |
| esac | |
| if [[ $DRY_RUN -eq 1 ]]; then | |
| printf "[DRY-RUN] rm -rf -- %q\n" "$path" | |
| return 0 | |
| fi | |
| if [[ -e "$path" ]]; then | |
| printf "[REMOVE] %s\n" "$path" | |
| rm -rf -- "$path" | |
| else | |
| printf "[SKIP] Not found: %s\n" "$path" | |
| fi | |
| } | |
| # Show what we plan to do | |
| info "Planned removals:" | |
| for t in "${TARGETS[@]}"; do | |
| if [[ -e "$t" ]]; then | |
| printf " - %s (exists)\n" "$t" | |
| else | |
| printf " - %s (not found)\n" "$t" | |
| fi | |
| done | |
| # Confirmation prompt unless --force or --dry-run | |
| if [[ $FORCE -ne 1 && $DRY_RUN -ne 1 ]]; then | |
| printf "\nAbout to remove the items above.\n" | |
| printf "Type YES to proceed: " | |
| read -r REPLY | |
| if [[ "$REPLY" != "YES" ]]; then | |
| error "Aborted by user." | |
| fi | |
| fi | |
| # Perform removals | |
| for t in "${TARGETS[@]}"; do | |
| safe_rm "$t" | |
| done | |
| # Verification listings similar to the PDF steps | |
| printf "\n[VERIFY] Listing %s\n" "$BASE/Library/Extensions" | |
| ls -la "$BASE/Library/Extensions" 2>/dev/null || true | |
| printf "\n[VERIFY] Listing %s\n" "$BASE/Library" | |
| ls -la "$BASE/Library" 2>/dev/null || true | |
| info "Completed. If you ran this from Recovery, restart into normal macOS." | |
| info "If some items persisted, try running again from Recovery mode with: --volume \"YourDiskName\"" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment