It might be worth noting that bash is a specific thing - that is, it refers to a specific shell. zsh is not bash, and there is nothing bash specific in the slightest in this article.
How about, instead of saying ..."just using bash", you wrote, ..."just using shell"?
Not safe at all. It relies on Spotlight (mdfind), which could return all kinds of things you might not want deleted. It pays no attention to BoM receipts. Why?! Then it just summarily deletes stuff (rm). See my much safer script above in comments.
This is bad form. First of all, we have a homebrew plug. homebrew makes a mess and...
Homebrew does not honor the default privileges of /usr/local; directory ownership is changed from root with group permissions for the wheel group to the installing user and the "admin" group. Specifically, the mode changes from drwxr-xr-x root wheel to drwxrwxr-x myuser admin. All files, not just the directories, have their ownership changed by the installer. This is considered by some as a major security flaw.[1]
MacPorts is superior and it is what the pros use. Now enough of that.
OP's method pays absolutely no attention to the BoM Receipts that every application installed with an installer will honor. This method doesn't consult the BoM, and obviously leaves stuff lying around.
BoMs are found in /var/db/receipts for all App Store installations and updates, and all other installations performed by the Installer app. macOS system, security, and security data updates have their BoMs stored in /System/Library/Receipts
Below somewhere is a superior uninstaller script I picked up at some point.
First install the appropriate version of Xcode for your macOS version. Then install MacPorts package manager thusly:
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.7.2.tar.bz2
tar xjvf MacPorts-2.7.2.tar.bz2
cd MacPorts-2.7.2/
./configure
make
sudo make install #not war!
cd ..
sudo rm -rf Macports-*
sudo /opt/local/bin/port -vs selfupdate
Then drop below in a file in your ~/bin (or /usr/local/bin if you want all users to have access), maybe call it "uninstaller," and
chmod +x uninstaller
--------------------------
#!/bin/bash
#uninstall application installed with installer -pkg
#using (user) provided bom receipt
#place all installed files and directories in user's Trash
lsbom="/usr/bin/lsbom"
cd="/usr/bin/cd"
sudo="/usr/bin/sudo"
xargs="/usr/bin/xargs"
rmtrash="/opt/local/bin/rmtrash"
lsbom -fls "$1" | (cd /; sudo xargs rmtrash -u $USER)
exit
--------------------------
make sure to install rmtrash before using
sudo port -vsN install rmtrash
To make this clearer, user must find the BoM receipt and the path to the BoM for whatever application for the input for this script. Again find BoMs in /var/db/receipts or /System/Library/Receipts
So, for e.g., say you've installed an application called Test.app. First find the $PATH to the correct BoM then call its path with the script.
after entering password, this execution will uninstall everything that installer installed for Test.app because all those files are listed in the BoM, and it will move all files the Test.app installer installed into your Trash.
I think it is just nuts to use /bin/rm in a script like this, so rmtrash is a little cli utility that moves things into your Trash, rather than deleting immediately. Much safer. Also, my script does not rely on Spotlight (mdfind). No telling what mdfind will return. Use the Bill of Materials receipts to uninstall, not Spotlight. That's crazy talk.
I had not heard of trash! It seemed so strange to me that rmtrash was not named trash that I had aliased it. I'm not sure which came first, but if it was rmtrash.... how did the dev miss that? Probably a story there, unless rmtrash is newer.
The wiki says Apple Chip Macs use /opt/homebrew. Apple chip Macs is the direction for all Macs. What’s the issue with it then when /usr/local isn’t touched?
Also. Why not use both scripts? Both of them will miss stuff. Like when apps create weird random files to track licenses or trials.
Oh good, you pointed out another problem with homebrew, that it immediately abandons legacy systems, and apparently is inconsistent with those legacy systems.
MacPorts has been using /opt since 2002, works on Tiger and anything newer up to current. Homebrew came into existence superfluously in 2008 and only through fanaticism grew, and for no good reason, as it merely duplicated some of MacPorts functionality, focusing on binary installations. Eventually, Homebrew could also build from source, duplicating more of MacPorts functionality. Then I suppose in 2020, homebrew tried to wallpaper across MacPorts and use /opt, 18 years after /opt/local priority was established by MacPorts.
FWIW
/opt/homebrew does not actually conflict with /opt/local/
and if homebrew never honored system permissions, what makes you think it's going to start?
> Also. Why not use both scripts? Both of them will miss stuff. Like when apps create weird random files to track licenses or trials.
No, my script will uninstall everything the installer installed, because everything the installer installed is listed in the Bill of Materials. Any other files which were not installed by the installer can be considered documents. Uninstalling an application should not delete the documents, you can do that manually, including anything left in /Library or ~/Library(/Application Support etc.) that the application may have created but the installer did not install, because these, again, are documents, and should not be uninstalled, but instead manually deleted if desired.
I always wished for Mac OS or Unix in general to have a way to ‘stamp’ files with the application bundle id that created the file. Something in extended attributes, just like the quarantine tag that records where a download came from.
Does anyone have any idea on how you could make a wrapper that would be able to do this? If that’s possible, the next step would be to figure out how to have launchd use the wrapper. Or even better, swap out the Application.app with the wrapper and make the actual application hidden like .Application.app, or inside the wrapper, or …?
The wrapper would stamp itself and the original with the bundle id so when you do a find on the xattr of the bundle you get a definitive list of every last trace of everything on the filesystem related to the application.
Perhaps the wrapper would have a special case of documents created and saved in normal user home directories, so e.g. your ~/Documents/todo.txt created in MacVim doesn’t get the macvim tag
The reason for all this?
Some commercial software offers a trial and some licensing systems out there spew obfuscated files in weird places, that aren’t easily identified as belonging to the app or the licensing framework.
Regarding the very last line of your comment - I use BlockBlock (https://objective-see.com/products/blockblock.html) on every Mac to catch/stop software installing weird startup/background agents. Might be worth checking out.
14 comments
[ 3.4 ms ] story [ 41.4 ms ] threadHow about, instead of saying ..."just using bash", you wrote, ..."just using shell"?
How safe is this in the face of errors. Can you end up with a situation where you end up running a naked ‘rm -rf’ ?
https://freemacsoft.net/appcleaner/
Homebrew does not honor the default privileges of /usr/local; directory ownership is changed from root with group permissions for the wheel group to the installing user and the "admin" group. Specifically, the mode changes from drwxr-xr-x root wheel to drwxrwxr-x myuser admin. All files, not just the directories, have their ownership changed by the installer. This is considered by some as a major security flaw.[1]
MacPorts is superior and it is what the pros use. Now enough of that.
OP's method pays absolutely no attention to the BoM Receipts that every application installed with an installer will honor. This method doesn't consult the BoM, and obviously leaves stuff lying around.
BoMs are found in /var/db/receipts for all App Store installations and updates, and all other installations performed by the Installer app. macOS system, security, and security data updates have their BoMs stored in /System/Library/Receipts
Below somewhere is a superior uninstaller script I picked up at some point. First install the appropriate version of Xcode for your macOS version. Then install MacPorts package manager thusly:
Add this line to your ~/.bash_profile Then drop below in a file in your ~/bin (or /usr/local/bin if you want all users to have access), maybe call it "uninstaller," and -------------------------- --------------------------make sure to install rmtrash before using
To make this clearer, user must find the BoM receipt and the path to the BoM for whatever application for the input for this script. Again find BoMs in /var/db/receipts or /System/Library/ReceiptsSo, for e.g., say you've installed an application called Test.app. First find the $PATH to the correct BoM then call its path with the script.
after entering password, this execution will uninstall everything that installer installed for Test.app because all those files are listed in the BoM, and it will move all files the Test.app installer installed into your Trash.I think it is just nuts to use /bin/rm in a script like this, so rmtrash is a little cli utility that moves things into your Trash, rather than deleting immediately. Much safer. Also, my script does not rely on Spotlight (mdfind). No telling what mdfind will return. Use the Bill of Materials receipts to uninstall, not Spotlight. That's crazy talk.
[1] https://en.wikipedia.org/w...
[1] https://github.com/morgant/tools-osx/blob/master/src/trash
Also. Why not use both scripts? Both of them will miss stuff. Like when apps create weird random files to track licenses or trials.
Oh good, you pointed out another problem with homebrew, that it immediately abandons legacy systems, and apparently is inconsistent with those legacy systems.
MacPorts has been using /opt since 2002, works on Tiger and anything newer up to current. Homebrew came into existence superfluously in 2008 and only through fanaticism grew, and for no good reason, as it merely duplicated some of MacPorts functionality, focusing on binary installations. Eventually, Homebrew could also build from source, duplicating more of MacPorts functionality. Then I suppose in 2020, homebrew tried to wallpaper across MacPorts and use /opt, 18 years after /opt/local priority was established by MacPorts.
FWIW /opt/homebrew does not actually conflict with /opt/local/
and if homebrew never honored system permissions, what makes you think it's going to start?
> Also. Why not use both scripts? Both of them will miss stuff. Like when apps create weird random files to track licenses or trials.
No, my script will uninstall everything the installer installed, because everything the installer installed is listed in the Bill of Materials. Any other files which were not installed by the installer can be considered documents. Uninstalling an application should not delete the documents, you can do that manually, including anything left in /Library or ~/Library(/Application Support etc.) that the application may have created but the installer did not install, because these, again, are documents, and should not be uninstalled, but instead manually deleted if desired.
Does anyone have any idea on how you could make a wrapper that would be able to do this? If that’s possible, the next step would be to figure out how to have launchd use the wrapper. Or even better, swap out the Application.app with the wrapper and make the actual application hidden like .Application.app, or inside the wrapper, or …?
The wrapper would stamp itself and the original with the bundle id so when you do a find on the xattr of the bundle you get a definitive list of every last trace of everything on the filesystem related to the application.
Perhaps the wrapper would have a special case of documents created and saved in normal user home directories, so e.g. your ~/Documents/todo.txt created in MacVim doesn’t get the macvim tag
The reason for all this?
Some commercial software offers a trial and some licensing systems out there spew obfuscated files in weird places, that aren’t easily identified as belonging to the app or the licensing framework.