Skip to main content

Has anyone put together a policy/script to uninstall homebrew with Jamf?

They have an uninstall script located here:

https://github.com/homebrew/install#uninstall-homebrew

 

But if I upload that to Jamf and run it with "--quiet --force" it throws an error shown below.  Seems like something from Jamf is adding a "/" argument to the script and it's causing it to fail.  

Script exit code: 1 Script result: Warning: Unrecognized option: '/' Homebrew Uninstaller Usage: /Library/Application Support/JAMF/tmp/uninstallHomebrew.sh [options] -p, --path=PATH Sets Homebrew prefix. Defaults to /usr/local. --skip-cache-and-logs Skips removal of HOMEBREW_CACHE and HOMEBREW_LOGS. -f, --force Uninstall without prompting. -q, --quiet Suppress all output. -n, --dry-run Simulate uninstall but don't remove anything. -h, --help Display this message.

All scripts in JSS is called with 3 arguments

1) The root of the installation (usually / slash) this is causing the error message you got
2) The name of the computer
3) The user of the computer

Too fix this you have to remove these three arguments by using adding
shift 3
as the second line in the script.


All scripts in JSS is called with 3 arguments

1) The root of the installation (usually / slash) this is causing the error message you got
2) The name of the computer
3) The user of the computer

Too fix this you have to remove these three arguments by using adding
shift 3
as the second line in the script.


Hi @johandahl 

 

I tried that but no luck.  Here's how the start of the script looks.  First line is blank, second has a #, and then the 3rd is where the script starts.

 

# #!/bin/bash set -u shopt -s extglob abort() { printf "%s\\n" "$@" exit 1 }

 


The "#!..." must be the very first line of the script, otherwise the system will try to execute it in the current shell, which might or might not have use the same syntax. Before trying any changes to the script it might be useful to learn the basics of Unix scripting, in this particular case scripting in bash.


Hi @johandahl 

 

I tried that but no luck.  Here's how the start of the script looks.  First line is blank, second has a #, and then the 3rd is where the script starts.

 

# #!/bin/bash set -u shopt -s extglob abort() { printf "%s\\n" "$@" exit 1 }

 


My suggestion was to change the script so the beginning

 

#!/bin/bash set -u shopt -s extglob

 

would become

 

#!/bin/bash shift 3 # Remove / computername and user set -u shopt -s extglob

 


@johandahl "shift 3" helped. I wasn't aware bash had the built-in shift command.  So i was just thinking you had meant "shift 3" like a keyboard press (which would be a # character).  When i added "shift 3" to the second line of the script that did eliminate the first 3 parameters.  The homebrew script still threw an error saying "Warning: Unrecognized option: ''", but i was able to comment out that section and statically set the parameters from within the script, and that seems to have worked around the issue.  Thank you


@johandahl "shift 3" helped. I wasn't aware bash had the built-in shift command.  So i was just thinking you had meant "shift 3" like a keyboard press (which would be a # character).  When i added "shift 3" to the second line of the script that did eliminate the first 3 parameters.  The homebrew script still threw an error saying "Warning: Unrecognized option: ''", but i was able to comment out that section and statically set the parameters from within the script, and that seems to have worked around the issue.  Thank you


Nice I could help you 🙂


Mind sharing the modifications you made to get this running?


Mind sharing the modifications you made to get this running?


Sure.  The policy itself just runs the uninstallHomebrew.sh script and doesn't pass it any parameters (probably a better way to handle that to make it more flexible).

 

I make the first change johandahl suggested with shift:

#!/bin/bash shift 3 # this line gets added to ignore the 3 standard Jamf parameters set -u shopt -s extglob

Then i modify the default options so it uninstalls silently:

# Default options opt_force="1" opt_quiet="1" opt_dry_run="" opt_skip_cache_and_logs=""

Then i comment out the section that looks for parameters:

#while [[ $# -gt 0 ]] #do # case "$1" in # -p*) homebrew_prefix_candidates+=("${1#-p}") ;; # --path=*) homebrew_prefix_candidates+=("${1#--path=}") ;; # --skip-cache-and-logs) opt_skip_cache_and_logs=1 ;; # -f | --force) opt_force=1 ;; # -q | --quiet) opt_quiet=1 ;; # -d | -n | --dry-run) opt_dry_run=1 ;; # -h | --help) usage ;; # *) # warn "Unrecognized option: '$1'" # usage 1 # ;; # esac # shift #done

 

Its pretty rushed and hacked together, but when i run the policy on a system Homebrew is gone, and thats all that mattered to me.  Down the line it might be nice to tweak it in a way that i can use parameters again, but i don't need that flexibility at the moment.

 


Sure.  The policy itself just runs the uninstallHomebrew.sh script and doesn't pass it any parameters (probably a better way to handle that to make it more flexible).

 

I make the first change johandahl suggested with shift:

#!/bin/bash shift 3 # this line gets added to ignore the 3 standard Jamf parameters set -u shopt -s extglob

Then i modify the default options so it uninstalls silently:

# Default options opt_force="1" opt_quiet="1" opt_dry_run="" opt_skip_cache_and_logs=""

Then i comment out the section that looks for parameters:

#while [[ $# -gt 0 ]] #do # case "$1" in # -p*) homebrew_prefix_candidates+=("${1#-p}") ;; # --path=*) homebrew_prefix_candidates+=("${1#--path=}") ;; # --skip-cache-and-logs) opt_skip_cache_and_logs=1 ;; # -f | --force) opt_force=1 ;; # -q | --quiet) opt_quiet=1 ;; # -d | -n | --dry-run) opt_dry_run=1 ;; # -h | --help) usage ;; # *) # warn "Unrecognized option: '$1'" # usage 1 # ;; # esac # shift #done

 

Its pretty rushed and hacked together, but when i run the policy on a system Homebrew is gone, and thats all that mattered to me.  Down the line it might be nice to tweak it in a way that i can use parameters again, but i don't need that flexibility at the moment.

 


@Jason11 Are you willing to share your final Uninstall script for Homebrew? I'm trying to find a method for uninstalling as well.


@Jason11 Are you willing to share your final Uninstall script for Homebrew? I'm trying to find a method for uninstalling as well.


Hi @bcbackes , here's what I'm using currently:

#!/bin/bash shift 3 set -u shopt -s extglob abort() { printf "%s\\n" "$@" exit 1 } strip_s() { local s for s in "$@" do s="${s## }" echo "${s%% }" done } dir_children() { local p for p in "$@" do [[ -d "${p}" ]] || continue find "${p}" -mindepth 1 -maxdepth 1 done } # Set up temp dir tmpdir="/tmp/uninstall.$$" mkdir -p "${tmpdir}" || abort "Unable to create temp dir '${tmpdir}'" trap ' rm -fr "${tmpdir}" # Invalidate sudo timestamp before exiting /usr/bin/sudo -k ' EXIT # Default options opt_force="1" opt_quiet="1" opt_dry_run="" opt_skip_cache_and_logs="" # global status to indicate whether there is anything wrong. failed=false un="$(uname)" case "${un}" in Linux) ostype=linux homebrew_prefix_default=/home/linuxbrew/.linuxbrew ;; Darwin) ostype=macos if [[ "$(uname -m)" == "arm64" ]] then homebrew_prefix_default=/opt/homebrew else homebrew_prefix_default=/usr/local fi realpath() { cd "$(dirname "$1")" && echo "$(pwd -P)/$(basename "$1")" } ;; *) abort "Unsupported system type '${un}'" ;; esac # string formatters if [[ -t 1 ]] then tty_escape() { printf "\\033[%sm" "$1"; } else tty_escape() { :; } fi tty_mkbold() { tty_escape "1;${1:-39}"; } tty_blue="$(tty_mkbold 34)" tty_red="$(tty_mkbold 31)" tty_bold="$(tty_mkbold 39)" tty_reset="$(tty_escape 0)" have_sudo_access() { local -a args if [[ -n "${SUDO_ASKPASS-}" ]] then args=("-A") fi if [[ -z "${HAVE_SUDO_ACCESS-}" ]] then if [[ -n "${args[*]-}" ]] then /usr/bin/sudo "${args[@]}" -l mkdir &>/dev/null else /usr/bin/sudo -l mkdir &>/dev/null fi HAVE_SUDO_ACCESS="$?" fi if [[ -z "${HOMEBREW_ON_LINUX-}" ]] && [[ "${HAVE_SUDO_ACCESS}" -ne 0 ]] then abort "Need sudo access on macOS (e.g. the user ${USER} to be an Administrator)!" fi return "${HAVE_SUDO_ACCESS}" } shell_join() { local arg printf "%s" "$1" shift for arg in "$@" do printf " " printf "%s" "${arg// /\\ }" done } resolved_pathname() { realpath "$1"; } pretty_print_pathnames() { local p for p in "$@" do if [[ -L "${p}" ]] then printf '%s -> %s\\n' "${p}" "$(resolved_pathname "${p}")" elif [[ -d "${p}" ]] then echo "${p}/" else echo "${p}" fi done } chomp() { printf "%s" "${1/"$'\\n'"/}" } ohai() { printf "${tty_blue}==>${tty_bold} %s${tty_reset}\\n" "$(shell_join "$@")" } warn() { printf "${tty_red}Warning${tty_reset}: %s\\n" "$(chomp "$1")" } execute() { if ! "$@" then abort "$(printf "Failed during: %s" "$(shell_join "$@")")" fi } execute_sudo() { local -a args=("$@") if [[ -n "${SUDO_ASKPASS-}" ]] then args=("-A" "${args[@]}") fi if have_sudo_access then ohai "/usr/bin/sudo" "${args[@]}" system "/usr/bin/sudo" "${args[@]}" else ohai "${args[@]}" system "${args[@]}" fi } system() { if ! "$@" then warn "Failed during: $(shell_join "$@")" failed=true fi } ####################################################################### script homebrew_prefix_candidates=() usage() { cat <<EOS Homebrew Uninstaller Usage: $0 [options] -p, --path=PATH Sets Homebrew prefix. Defaults to ${homebrew_prefix_default}. --skip-cache-and-logs Skips removal of HOMEBREW_CACHE and HOMEBREW_LOGS. -f, --force Uninstall without prompting. -q, --quiet Suppress all output. -n, --dry-run Simulate uninstall but don't remove anything. -h, --help Display this message. EOS exit "${1:-0}" } #while [[ $# -gt 0 ]] #do # case "$1" in # -p*) homebrew_prefix_candidates+=("${1#-p}") ;; # --path=*) homebrew_prefix_candidates+=("${1#--path=}") ;; # --skip-cache-and-logs) opt_skip_cache_and_logs=1 ;; # -f | --force) opt_force=1 ;; # -q | --quiet) opt_quiet=1 ;; # -d | -n | --dry-run) opt_dry_run=1 ;; # -h | --help) usage ;; # *) # warn "Unrecognized option: '$1'" # usage 1 # ;; # esac # shift #done # Attempt to locate Homebrew unless `--path` is passed if [[ "${#homebrew_prefix_candidates[@]}" -eq 0 ]] then prefix="$(brew --prefix)" [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("${prefix}") prefix="$(command -v brew)" || prefix="" [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("$(dirname "$(dirname "$(strip_s "${prefix}")")")") homebrew_prefix_candidates+=("${homebrew_prefix_default}") # Homebrew default path homebrew_prefix_candidates+=("${HOME}/.linuxbrew") # Linuxbrew default path fi HOMEBREW_PREFIX="$( for p in "${homebrew_prefix_candidates[@]}" do [[ -d "${p}" ]] || continue [[ ${p} == "${homebrew_prefix_default}" && -d "${p}/Homebrew/.git" ]] && echo "${p}" && break [[ -d "${p}/.git" || -x "${p}/bin/brew" ]] && echo "${p}" && break done )" [[ -n "${HOMEBREW_PREFIX}" ]] || abort "Failed to locate Homebrew!" if [[ -d "${HOMEBREW_PREFIX}/.git" ]] then HOMEBREW_REPOSITORY="$(dirname "$(realpath "${HOMEBREW_PREFIX}/.git")")" elif [[ -x "${HOMEBREW_PREFIX}/bin/brew" ]] then HOMEBREW_REPOSITORY="$(dirname "$(dirname "$(realpath "${HOMEBREW_PREFIX}/bin/brew")")")" else abort "Failed to locate Homebrew!" fi if [[ -d "${HOMEBREW_PREFIX}/Cellar" ]] then HOMEBREW_CELLAR="${HOMEBREW_PREFIX}/Cellar" else HOMEBREW_CELLAR="${HOMEBREW_REPOSITORY}/Cellar" fi if [[ -s "${HOMEBREW_REPOSITORY}/.gitignore" ]] then gitignore="$(<"${HOMEBREW_REPOSITORY}/.gitignore")" else gitignore="$(curl -fsSL https://raw.githubusercontent.com/Homebrew/brew/HEAD/.gitignore)" fi [[ -n "${gitignore}" ]] || abort "Failed to fetch Homebrew .gitignore!" { while read -r l do [[ "${l}" == \\!* ]] || continue l="${l#\\!}" l="${l#/}" [[ "${l}" == @(bin|share|share/doc) ]] && echo "REJECT: ${l}" >&2 && continue echo "${HOMEBREW_REPOSITORY}/${l}" done <<<"${gitignore}" if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" ]] then echo "${HOMEBREW_REPOSITORY}" directories=( bin/brew etc/bash_completion.d/brew share/doc/homebrew share/man/man1/brew.1 share/man/man1/brew-cask.1 share/man/man1/README.md share/zsh/site-functions/_brew share/zsh/site-functions/_brew_cask share/fish/vendor_completions.d/brew.fish var/homebrew ) for p in "${directories[@]}" do echo "${HOMEBREW_PREFIX}/${p}" done else echo "${HOMEBREW_REPOSITORY}/.git" fi echo "${HOMEBREW_CELLAR}" echo "${HOMEBREW_PREFIX}/Caskroom" [[ -n ${opt_skip_cache_and_logs} ]] || cat <<-EOS ${HOME}/Library/Caches/Homebrew ${HOME}/Library/Logs/Homebrew /Library/Caches/Homebrew ${HOME}/.cache/Homebrew ${HOMEBREW_CACHE:-} ${HOMEBREW_LOGS:-} EOS if [[ "${ostype}" == macos ]] then dir_children "/Applications" "${HOME}/Applications" | while read -r p2; do [[ $(resolved_pathname "${p2}") == "${HOMEBREW_CELLAR}"/* ]] && echo "${p2}" done fi } | while read -r l; do [[ -e "${l}" ]] && echo "${l}" done | sort -u >"${tmpdir}/homebrew_files" homebrew_files=() while read -r l do homebrew_files+=("${l}") done <"${tmpdir}/homebrew_files" if [[ -z "${opt_quiet}" ]] then dry_str="${opt_dry_run:+would}" warn "This script ${dry_str:-will} remove:" pretty_print_pathnames "${homebrew_files[@]}" fi if [[ -t 0 && -z "${opt_force}" && -z "${opt_dry_run}" ]] then read -rp "Are you sure you want to uninstall Homebrew? This will remove your installed packages! [y/N] " [[ "${REPLY}" == [yY]* ]] || abort fi [[ -n "${opt_quiet}" ]] || ohai "Removing Homebrew installation..." paths=() for p in Frameworks bin etc include lib opt sbin share var do p="${HOMEBREW_PREFIX}/${p}" [[ -e "${p}" ]] && paths+=("${p}") done if [[ "${#paths[@]}" -gt 0 ]] then if [[ "${ostype}" == macos ]] then args=(-E "${paths[@]}" -regex '.*/info/([^.][^/]*\\.info|dir)') else args=("${paths[@]}" -regextype posix-extended -regex '.*/info/([^.][^/]*\\.info|dir)') fi if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would delete:" else args+=(-exec /bin/bash -c) args+=("/usr/bin/install-info --delete --quiet {} \\"\\$(dirname {})/dir\\"") args+=(';') fi system /usr/bin/find "${args[@]}" args=("${paths[@]}" -type l -lname '*/Cellar/*') if [[ -n "${opt_dry_run}" ]] then args+=(-print) else args+=(-exec unlink '{}' ';') fi [[ -n "${opt_dry_run}" ]] && echo "Would delete:" system /usr/bin/find "${args[@]}" fi for file in "${homebrew_files[@]}" do if [[ -n "${opt_dry_run}" ]] then echo "Would delete ${file}" else if ! err="$(rm -fr "${file}" 2>&1)" then warn "Failed to delete ${file}" echo "${err}" fi fi done sudo() { ohai "/usr/bin/sudo" "$@" system /usr/bin/sudo "$@" } [[ -n "${opt_quiet}" ]] || ohai "Removing empty directories..." paths=() for p in bin etc include lib opt sbin share var Caskroom Cellar Homebrew Frameworks do p="${HOMEBREW_PREFIX}/${p}" [[ -e "${p}" ]] && paths+=("${p}") done if [[ "${#paths[@]}" -gt 0 ]] then if [[ "${ostype}" == macos ]] then args=("${paths[@]}" -name .DS_Store) if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would delete:" else args+=(-delete) fi execute_sudo /usr/bin/find "${args[@]}" fi args=("${paths[@]}" -depth -type d -empty) if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would remove directories:" else args+=(-exec rmdir '{}' ';') fi execute_sudo /usr/bin/find "${args[@]}" fi [[ -n "${opt_dry_run}" ]] && exit if [[ "${HOMEBREW_PREFIX}" != "${homebrew_prefix_default}" && -e "${HOMEBREW_PREFIX}" ]] then execute_sudo rmdir "${HOMEBREW_PREFIX}" fi if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" && -e "${HOMEBREW_REPOSITORY}" ]] then execute_sudo rmdir "${HOMEBREW_REPOSITORY}" fi if [[ -z "${opt_quiet}" ]] then if [[ "${failed}" == true ]] then warn "Homebrew partially uninstalled (but there were steps that failed)!" echo "To finish uninstalling rerun this script with \\`sudo\\`." else ohai "Homebrew uninstalled!" fi fi dir_children "${HOMEBREW_REPOSITORY}" "${HOMEBREW_PREFIX}" | sort -u >"${tmpdir}/residual_files" if [[ -s "${tmpdir}/residual_files" && -z "${opt_quiet}" ]] then echo "The following possible Homebrew files were not deleted:" while read -r f do pretty_print_pathnames "${f}" done <"${tmpdir}/residual_files" echo -e "You may wish to remove them yourself.\\n" fi [[ "${failed}" != true ]]
#!/bin/bash NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)" /bin/rm -rf /opt/homebrew exit 0

https://github.com/homebrew/install#uninstall-homebrew


#!/bin/bash NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)" /bin/rm -rf /opt/homebrew exit 0

https://github.com/homebrew/install#uninstall-homebrew


The script (from JP) will need to be run as the user and not as the jamf pro account.

I would add:

usr="$(/usr/bin/stat -f %Su /dev/console)"

/usr/bin/sudo -i -u "$usr" <the uninstall command>


Old post but here's what I'm currently using see below. I got it from here:
https://github.com/homebrew/install#uninstall-homebrew https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh

#!/bin/bash # We don't need return codes for "$(command)", only stdout is needed. # Allow `[[ -n "$(command)" ]]`, `func "$(command)"`, pipes, etc. # shellcheck disable=SC2312 set -u abort() { printf "%s\\n" "$@" >&2 exit 1 } # Fail fast with a concise message when not using bash # Single brackets are needed here for POSIX compatibility # shellcheck disable=SC2292 if [ -z "${BASH_VERSION:-}" ] then abort "Bash is required to interpret this script." fi shopt -s extglob strip_s() { local s for s in "$@" do s="${s## }" echo "${s%% }" done } dir_children() { local p for p in "$@" do [[ -d "${p}" ]] || continue find "${p}" -mindepth 1 -maxdepth 1 done } # Set up temp dir tmpdir="/tmp/uninstall.$$" mkdir -p "${tmpdir}" || abort "Unable to create temp dir '${tmpdir}'" trap ' rm -fr "${tmpdir}" # Invalidate sudo timestamp before exiting /usr/bin/sudo -k ' EXIT # Default options opt_force="" opt_quiet="" opt_dry_run="" opt_skip_cache_and_logs="" # global status to indicate whether there is anything wrong. failed=false un="$(uname)" case "${un}" in Linux) ostype=linux homebrew_prefix_default=/home/linuxbrew/.linuxbrew ;; Darwin) ostype=macos if [[ "$(uname -m)" == "arm64" ]] then homebrew_prefix_default=/opt/homebrew else homebrew_prefix_default=/usr/local fi realpath() { cd "$(dirname "$1")" && echo "$(pwd -P)/$(basename "$1")" } ;; *) abort "Unsupported system type '${un}'" ;; esac # string formatters if [[ -t 1 ]] then tty_escape() { printf "\\033[%sm" "$1"; } else tty_escape() { :; } fi tty_mkbold() { tty_escape "1;${1:-39}"; } tty_blue="$(tty_mkbold 34)" tty_red="$(tty_mkbold 31)" tty_bold="$(tty_mkbold 39)" tty_reset="$(tty_escape 0)" unset HAVE_SUDO_ACCESS # unset this from the environment have_sudo_access() { if [[ ! -x "/usr/bin/sudo" ]] then return 1 fi local -a SUDO=("/usr/bin/sudo") if [[ -n "${SUDO_ASKPASS-}" ]] then SUDO+=("-A") fi if [[ -z "${HAVE_SUDO_ACCESS-}" ]] then "${SUDO[@]}" -l mkdir &>/dev/null HAVE_SUDO_ACCESS="$?" fi if [[ -z "${HOMEBREW_ON_LINUX-}" ]] && [[ "${HAVE_SUDO_ACCESS}" -ne 0 ]] then abort "Need sudo access on macOS (e.g. the user ${USER} needs to be an administrator)!" fi return "${HAVE_SUDO_ACCESS}" } shell_join() { local arg printf "%s" "$1" shift for arg in "$@" do printf " " printf "%s" "${arg// /\\ }" done } resolved_pathname() { realpath "$1"; } pretty_print_pathnames() { local p for p in "$@" do if [[ -L "${p}" ]] then printf '%s -> %s\\n' "${p}" "$(resolved_pathname "${p}")" elif [[ -d "${p}" ]] then echo "${p}/" else echo "${p}" fi done } chomp() { printf "%s" "${1/"$'\\n'"/}" } ohai() { printf "${tty_blue}==>${tty_bold} %s${tty_reset}\\n" "$(shell_join "$@")" } warn() { printf "${tty_red}Warning${tty_reset}: %s\\n" "$(chomp "$1")" } execute() { if ! "$@" then abort "$(printf "Failed during: %s" "$(shell_join "$@")")" fi } execute_sudo() { local -a args=("$@") if have_sudo_access then if [[ -n "${SUDO_ASKPASS-}" ]] then args=("-A" "${args[@]}") fi ohai "/usr/bin/sudo" "${args[@]}" system "/usr/bin/sudo" "${args[@]}" else ohai "${args[@]}" system "${args[@]}" fi } system() { if ! "$@" then warn "Failed during: $(shell_join "$@")" failed=true fi } ####################################################################### script homebrew_prefix_candidates=() usage() { cat <<EOS Homebrew Uninstaller Usage: $0 [options] -p, --path=PATH Sets Homebrew prefix. Defaults to ${homebrew_prefix_default}. --skip-cache-and-logs Skips removal of HOMEBREW_CACHE and HOMEBREW_LOGS. -f, --force Uninstall without prompting. -q, --quiet Suppress all output. -n, --dry-run Simulate uninstall but don't remove anything. -h, --help Display this message. EOS exit "${1:-0}" } while [[ $# -gt 0 ]] do case "$1" in -p*) homebrew_prefix_candidates+=("${1#-p}") ;; --path=*) homebrew_prefix_candidates+=("${1#--path=}") ;; --skip-cache-and-logs) opt_skip_cache_and_logs=1 ;; -f | --force) opt_force=1 ;; -q | --quiet) opt_quiet=1 ;; -d | -n | --dry-run) opt_dry_run=1 ;; -h | --help) usage ;; *) warn "Unrecognized option: '$1'" usage 1 ;; esac shift done # Attempt to locate Homebrew unless `--path` is passed if [[ "${#homebrew_prefix_candidates[@]}" -eq 0 ]] then prefix="$(brew --prefix)" [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("${prefix}") prefix="$(command -v brew)" || prefix="" [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("$(dirname "$(dirname "$(strip_s "${prefix}")")")") homebrew_prefix_candidates+=("${homebrew_prefix_default}") # Homebrew default path homebrew_prefix_candidates+=("${HOME}/.linuxbrew") # Linuxbrew default path fi HOMEBREW_PREFIX="$( for p in "${homebrew_prefix_candidates[@]}" do [[ -d "${p}" ]] || continue [[ ${p} == "${homebrew_prefix_default}" && -d "${p}/Homebrew/.git" ]] && echo "${p}" && break [[ -d "${p}/.git" || -x "${p}/bin/brew" ]] && echo "${p}" && break done )" [[ -n "${HOMEBREW_PREFIX}" ]] || abort "Failed to locate Homebrew!" if [[ -d "${HOMEBREW_PREFIX}/.git" ]] then HOMEBREW_REPOSITORY="$(dirname "$(realpath "${HOMEBREW_PREFIX}/.git")")" elif [[ -x "${HOMEBREW_PREFIX}/bin/brew" ]] then HOMEBREW_REPOSITORY="$(dirname "$(dirname "$(realpath "${HOMEBREW_PREFIX}/bin/brew")")")" else abort "Failed to locate Homebrew!" fi if [[ -d "${HOMEBREW_PREFIX}/Cellar" ]] then HOMEBREW_CELLAR="${HOMEBREW_PREFIX}/Cellar" else HOMEBREW_CELLAR="${HOMEBREW_REPOSITORY}/Cellar" fi if [[ -s "${HOMEBREW_REPOSITORY}/.gitignore" ]] then gitignore="$(<"${HOMEBREW_REPOSITORY}/.gitignore")" else gitignore="$(curl -fsSL https://raw.githubusercontent.com/Homebrew/brew/HEAD/.gitignore)" fi [[ -n "${gitignore}" ]] || abort "Failed to fetch Homebrew .gitignore!" { while read -r l do [[ "${l}" == \\!* ]] || continue l="${l#\\!}" l="${l#/}" [[ "${l}" == @(bin|share|share/doc) ]] && echo "REJECT: ${l}" >&2 && continue echo "${HOMEBREW_REPOSITORY}/${l}" done <<<"${gitignore}" if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" ]] then echo "${HOMEBREW_REPOSITORY}" directories=( bin/brew etc/bash_completion.d/brew share/doc/homebrew share/man/man1/brew.1 share/man/man1/brew-cask.1 share/man/man1/README.md share/zsh/site-functions/_brew share/zsh/site-functions/_brew_cask share/fish/vendor_completions.d/brew.fish var/homebrew ) for p in "${directories[@]}" do echo "${HOMEBREW_PREFIX}/${p}" done else echo "${HOMEBREW_REPOSITORY}/.git" fi echo "${HOMEBREW_CELLAR}" echo "${HOMEBREW_PREFIX}/Caskroom" [[ -n ${opt_skip_cache_and_logs} ]] || cat <<-EOS ${HOME}/Library/Caches/Homebrew ${HOME}/Library/Logs/Homebrew /Library/Caches/Homebrew ${HOME}/.cache/Homebrew ${HOMEBREW_CACHE:-} ${HOMEBREW_LOGS:-} EOS if [[ "${ostype}" == macos ]] then dir_children "/Applications" "${HOME}/Applications" | while read -r p2; do [[ $(resolved_pathname "${p2}") == "${HOMEBREW_CELLAR}"/* ]] && echo "${p2}" done fi } | while read -r l; do [[ -e "${l}" ]] && echo "${l}" done | sort -u >"${tmpdir}/homebrew_files" homebrew_files=() while read -r l do homebrew_files+=("${l}") done <"${tmpdir}/homebrew_files" if [[ -z "${opt_quiet}" ]] then dry_str="${opt_dry_run:+would}" warn "This script ${dry_str:-will} remove:" pretty_print_pathnames "${homebrew_files[@]}" fi if [[ -t 0 && -z "${opt_force}" && -z "${opt_dry_run}" ]] then read -rp "Are you sure you want to uninstall Homebrew? This will remove your installed packages! [y/N] " [[ "${REPLY}" == [yY]* ]] || abort fi [[ -n "${opt_quiet}" ]] || ohai "Removing Homebrew installation..." paths=() for p in Frameworks bin etc include lib opt sbin share var do p="${HOMEBREW_PREFIX}/${p}" [[ -e "${p}" ]] && paths+=("${p}") done if [[ "${#paths[@]}" -gt 0 ]] then if [[ "${ostype}" == macos ]] then args=(-E "${paths[@]}" -regex '.*/info/([^.][^/]*\\.info|dir)') else args=("${paths[@]}" -regextype posix-extended -regex '.*/info/([^.][^/]*\\.info|dir)') fi if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would delete:" else args+=(-exec /bin/bash -c) args+=("/usr/bin/install-info --delete --quiet {} \\"\\$(dirname {})/dir\\"") args+=(';') fi system /usr/bin/find "${args[@]}" args=("${paths[@]}" -type l -lname '*/Cellar/*') if [[ -n "${opt_dry_run}" ]] then args+=(-print) else args+=(-exec unlink '{}' ';') fi [[ -n "${opt_dry_run}" ]] && echo "Would delete:" system /usr/bin/find "${args[@]}" fi for file in "${homebrew_files[@]}" do if [[ -n "${opt_dry_run}" ]] then echo "Would delete ${file}" else if ! err="$(rm -fr "${file}" 2>&1)" then warn "Failed to delete ${file}" echo "${err}" fi fi done [[ -n "${opt_quiet}" ]] || ohai "Removing empty directories..." paths=() for p in bin etc include lib opt sbin share var Caskroom Cellar Homebrew Frameworks do p="${HOMEBREW_PREFIX}/${p}" [[ -e "${p}" ]] && paths+=("${p}") done if [[ "${#paths[@]}" -gt 0 ]] then if [[ "${ostype}" == macos ]] then args=("${paths[@]}" -name .DS_Store) if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would delete:" else args+=(-delete) fi execute_sudo /usr/bin/find "${args[@]}" fi args=("${paths[@]}" -depth -type d -empty) if [[ -n "${opt_dry_run}" ]] then args+=(-print) echo "Would remove directories:" else args+=(-exec rmdir '{}' ';') fi execute_sudo /usr/bin/find "${args[@]}" fi [[ -n "${opt_dry_run}" ]] && exit if [[ "${HOMEBREW_PREFIX}" != "${homebrew_prefix_default}" && -e "${HOMEBREW_PREFIX}" ]] then execute_sudo rmdir "${HOMEBREW_PREFIX}" fi if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" && -e "${HOMEBREW_REPOSITORY}" ]] then execute_sudo rmdir "${HOMEBREW_REPOSITORY}" fi if [[ -z "${opt_quiet}" ]] then if [[ "${failed}" == true ]] then warn "Homebrew partially uninstalled (but there were steps that failed)!" echo "To finish uninstalling rerun this script with \\`sudo\\`." else ohai "Homebrew uninstalled!" fi fi dir_children "${HOMEBREW_REPOSITORY}" "${HOMEBREW_PREFIX}" | sort -u >"${tmpdir}/residual_files" if [[ -s "${tmpdir}/residual_files" && -z "${opt_quiet}" ]] then echo "The following possible Homebrew files were not deleted:" while read -r f do pretty_print_pathnames "${f}" done <"${tmpdir}/residual_files" echo -e "You may wish to remove them yourself.\\n" fi [[ "${failed}" != true ]]