diff --git a/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/README.md b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/README.md new file mode 100644 index 0000000..2e8db65 --- /dev/null +++ b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/README.md @@ -0,0 +1,40 @@ + + +# How to clean uninstall apps on macOS (an open source alternative to AppCleaner by FreeMacSoft) + +## Guide + +### Step 1: create `/usr/local/bin` folder + +```shell +sudo mkdir -p /usr/local/bin +sudo chown $(whoami):admin /usr/local/bin +``` + +### Step 2: download [app-cleaner.sh](app-cleaner.sh) ([PGP signature](./app-cleaner.sh.sig), [PGP public key](https://sunknudsen.com/sunknudsen.asc)) + +```shell +curl -o /usr/local/bin/app-cleaner.sh https://sunknudsen.com/static/media/privacy-guides/how-to-clean-uninstall-apps-on-macos/app-cleaner.sh +chmod +x /usr/local/bin/app-cleaner.sh +``` + +## Usage + +```console +$ app-cleaner.sh /Applications/AppCleaner.app +Checking for running processes... +Finding application data... +/Applications/AppCleaner.app +/Users/johndoe/Library/Preferences/net.freemacsoft.AppCleaner.plist +/Users/johndoe/Library/Saved Application State/net.freemacsoft.AppCleaner.savedState +Move application data to trash (y or n)? y +Moving application data to trash... +Done +``` diff --git a/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh new file mode 100755 index 0000000..ab3d423 --- /dev/null +++ b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh @@ -0,0 +1,119 @@ +#! /bin/sh + +if [ -z "$1" ]; then + printf "%s\n" "Usage: app-cleaner.sh /path/to/app.app" + exit 1 +fi + +IFS=$'\n' + +red=$'\e[1;31m' +nc=$'\e[0m' + +if [ ! -e "$1/Contents/Info.plist" ]; then + printf "%s\n" "Cannot find app plist" + exit 1 +fi + +bundle_identifier=$(/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" "$1/Contents/Info.plist" 2> /dev/null) + +if [ "$bundle_identifier" = "" ]; then + printf "%s\n" "Cannot find app bundle identifier" + exit 1 +fi + +printf "%s\n" "Checking for running processes..." +sleep 1 + +app_name=$(basename $1 .app) + +processes=($(pgrep -afil "$app_name" | grep -v "app-cleaner.sh")) + +if [ ${#processes[@]} -gt 0 ]; then + printf "%s\n" "${processes[@]}" + printf "${red}%s${nc}" "Kill running processes (y or n)? " + read -r answer + if [ "$answer" = "y" ]; then + printf "%s\n" "Killing running processes..." + sleep 1 + for process in "${processes[@]}"; do + echo $process | awk '{print $1}' | xargs kill + done + fi +fi + +home_dir=~ + +paths=() + +paths+=($(find /private/var/db/receipts -iname "*$app_name*.bom" -maxdepth 1 -prune 2>&1 | grep -av "Permission denied")) +paths+=($(find /private/var/db/receipts -iname "*$bundle_identifier*.bom" -maxdepth 1 -prune 2>&1 | grep -av "Permission denied")) + +if [ ${#paths[@]} -gt 0 ]; then + printf "%s\n" "Saving bill of material logs to desktop..." + sleep 1 + for path in "${paths[@]}"; do + mkdir -p "$home_dir/Desktop/$app_name" + lsbom -f -l -s -p f $path > "$home_dir/Desktop/$app_name/$(basename $path).log" + done +fi + +printf "%s\n" "Finding app data..." +sleep 1 + +locations=( + "$home_dir/Library" + "$home_dir/Library/Application Support" + "$home_dir/Library/Application Support/CrashReporter" + "$home_dir/Library/Containers" + "$home_dir/Library/Caches" + "$home_dir/Library/Group Containers" + "$home_dir/Library/Internet Plug-Ins" + "$home_dir/Library/LaunchAgents" + "$home_dir/Library/Logs" + "$home_dir/Library/Preferences" + "$home_dir/Library/Saved Application State" + "$home_dir/Library/WebKit" + "/Library" + "/Library/Application Support" + "/Library/Application Support/CrashReporter" + "/Library/Caches" + "/Library/Extensions" + "/Library/Internet Plug-Ins" + "/Library/LaunchAgents" + "/Library/LaunchDaemons" + "/Library/Logs" + "/Library/Preferences" + "/private/var/db/receipts" + "/usr/local/bin" + "/usr/local/etc" + "/usr/local/opt" + "/usr/local/sbin" + "/usr/local/share" + "/usr/local/var" +) + +paths=($1) + +for location in "${locations[@]}"; do + paths+=($(find "$location" -iname "*$app_name*" -maxdepth 1 -prune 2>&1 | grep -av "No such file or directory" | grep -av "Permission denied")) +done + +for location in "${locations[@]}"; do + paths+=($(find "$location" -iname "*$bundle_identifier*" -maxdepth 1 -prune 2>&1 | grep -av "No such file or directory" | grep -av "Permission denied")) +done + +paths=($(printf "%s\n" "${paths[@]}" | sort -u)); + +printf "%s\n" "${paths[@]}" + +printf "${red}%s${nc}" "Move app data to trash (y or n)? " +read -r answer +if [ "$answer" = "y" ]; then + printf "%s\n" "Moving app data to trash..." + sleep 1 + for path in "${paths[@]}"; do + osascript -e "tell application \"Finder\" to delete POSIX file \"$path\"" > /dev/null + done + printf "%s\n" "Done" +fi diff --git a/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh.sig b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh.sig new file mode 100644 index 0000000..54b810f Binary files /dev/null and b/how-to-clean-uninstall-apps-on-macos-an-open-source-alternative-to-appcleaner-by-freemacsoft/app-cleaner.sh.sig differ