Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Minghold

macrumors 6502a
Original poster
It's easy enough to remove a few icons with a ctrl/right-click. Removing dozens after a full Adobe, Office, and misc other apps trash-drag uninstall purge is a whole 'nother. --Are there any utilities (or procedures) that do this one thing well: determine the linked status of all icons on the dock, then kick all unlinked/broken/question-marks off the dock?
 
Hmm, the best that I could come up with from the interwebs was Terminal command:

defaults write com.apple.dock persistent-apps -array; killall Dock

to clear all the pinned (user created) apps from the dock but that doesn’t sound like that is exactly what you’re asking. Maybe someone else will chime in.
 
  • Like
Reactions: Minghold
It seems to me like a shell script could do most or all of this.

For example, here's a piece that outputs all the target apps:
defaults read com.apple.dock | grep _CFURLString

If the pathname for any of the apps no longer resolves, then its dock icon should be kicked out.

As for kicking an icon off the Dock in a script. I started with search terms:
remove mac dock icon script

and found this (among others):
and it linked to this that has details:
 
I've been fiddling with this for a bit, working with smaller pieces intended for a shell pipeline.

It was complicated by the fact that each of the older OSes I tested on had a different representation for the app's pathname in the Dock plist:
Snow Lep : "/Applications/Utilities/Activity Monitor.app/"
Mtn Lion : "file://localhost/Applications/Utilities/Activity%20Monitor.app/"
Sierra : "file:///Applications/Utilities/Activity%20Monitor.app/"

I think it's quite possible that other forms may be used by other OS versions.

Here are the shell functions I have so far. It's all in 'bash', and I didn't test in 'zsh', so test before actually using.
Code:
function dock_apps ()
{
  local PLIST="${1:-com.apple.dock}"
  echo >&2  " # -- $PLIST"
  defaults read "$PLIST" persistent-apps  \
  | grep CFURLString\"  \
  | tr -d "\";"  \
  | awk '{ print $3,$4,$5 }'
}
# The $3,$4,$5 is for Snow Leopard's com.apple.dock data.
# It's needed because app pathnames may contain blanks,
# such as "Disk Utility" or "Address Book".
# Fields $4,$5 etc. are empty if pathname is URL-encoded,
# so there's no ill effect on Mtn Lion or Sierra data.


function dock_fix ()
{
  awk '{ sub( /file:\/\/localhost/, "" );  print }'  \
  | awk '{ sub( /file:\/\//, "" );  print }'
}
# sub() operates on entire line if no src string given.


# urldecode() is from:
#  https://stackoverflow.com/questions/6250698/how-to-decode-url-encoded-string-in-shell

function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }

function dock_eval ()
{
  for (( NN=0; 1; ++NN ))
  do
    read ITEM || break;
    CLEAN=$( urldecode "$ITEM" );
    OK="del";
    [[ -d "$CLEAN" ]] && OK=" ok";
    echo " $OK  $NN  $CLEAN";
  done
}
These are designed to be used in a pipeline, with an optional arg to 'dock_apps' that designates a plist file different from the default "com.apple.dock".

One thing I did right away was to duplicate the existing plist in the ~/Library/Preferences dir and name it "FAKE.dock.plist", so I could work on a plist without inadvertantly mangling my Dock configuration. None of the functions so far do any writing to any plist, so they should be safe to use on the real Dock plist. If you're unsure, make your own "FAKE.dock.plist".

Example usage:
Code:
dock_apps | dock_fix | dock_eval
The output will be a series of lines starting with either "ok" if the Dock icon is ok, or "del" if not. Then there's a number, which is the zero-based index (position) in the persistent-apps array. That's the datum that PlistBuddy will need. Finally, there's the pathname of the app, which is mainly for humans.

Example output lines:
Code:
  ok  6  /Applications/Utilities/Disk Utility.app/
 del  7  /Applications/Mission Control.app/
This is from a run on Snow Leopard using a plist file copied from Sierra, which is why there's no "Mission Control" app.

So far, all this does is evaluate whether a Dock icon refers to a valid app bundle or not (the -d test in dock_eval). It doesn't make any changes to the Dock's plist yet.

Below is the function that converts dock_eval's output into a series of PlistBuddy commands, intended to be piped to that process's stdin. I haven't started testing it on a live Dock yet, because it will take some time to create a test user account where I can easily put app references into the Dock and then break them. I'll probably setup a couple of apps, say "Mole.app" and "Groundhog.app", and move them between two dirs, so they disappear from their original pathname dir but reappear in another.

Code:
function dock_buddy ()
{
  sort -k 2,2nr  \
  | awk ' ( $1 == "del" ) {
   print "delete persistent-apps:" $2 }
   END { print "save"; print "exit"; } '
}

# Example usage
dock_apps | dock_fix | dock_eval | dock_buddy

The dock_buddy output omits all the "ok" lines and app names, because only the index is significant for PlistBuddy. Also note that it starts deleting from the last entry and works down. This ensures that index positions are stable while the deletions are happening.

If run on a Dock where all the icons are valid, the only output should be this:
Code:
 # -- com.apple.dock
save
exit
The first line is output from dock_apps stderr, so isn't part of the subsequent pipeline.
 
I've done some testing on Sierra and Snow Leopard, and confirmed that the pipeline works. Here's the typical pipeline:
Code:
dock_apps | dock_fix | dock_eval | dock_buddy  \
  | /usr/libexec/PlistBuddy   ~/Library/Preferences/com.apple.dock.plist
Select both lines and paste into a Terminal window. It will also work to paste these into a plain text file and make a shell script, including all the function definitions from the above post

There will be some output that appears on the Terminal. One line is due to the 'echo' that shows where the data is coming from. The other lines or line-fragments are the interactive "Command:" prompts emitted by PlistBuddy, along with its interactive "Saving" output. That output looks something like this:
Code:
 # -- com.apple.dock
Command: Command: Command: Saving...
After the pipeline finishes, which should only take a second or so, you then need to kill the Dock process, so it relaunches with the modified preferences file. I know of two ways to do this. Pick one. My testing shows they both work the same.
Code:
killall Dock

osascript -e 'tell app "Dock" to quit'


Here's some example output from my testing. It's the output of the "short" pipeline that ends with dock_eval.
Code:
dock_apps | dock_fix | dock_eval 

 # -- com.apple.dock
  ok  0  /Applications/System Preferences.app/
  ok  1  /Applications/Utilities/Terminal.app/
  ok  2  /Applications/TextEdit.app/
  ok  3  /Applications/Launchpad.app/
 del  4  /Users/Shared/Whac/A/Mole.app/
  ok  5  /Applications/Safari.app/
  ok  6  /Applications/Mail.app/
  ok  7  /Applications/Contacts.app/
 del  8  /Users/Shared/Whac/A/Gopher.app/
  ok  9  /Applications/iBooks.app/
  ok  10  /Applications/App Store.app/
I made the test apps Mole.app and Gopher.app by copying and pasting the Grab.app from the Utilities folder, then renaming each one. It's small and doesn't do much when launched.

After dragging those apps into my Dock, I used the 'mv' command to move them to Whac/B. This caused the pathnames in the Dock's file to become invalid, as signalled by the 'del'.

Note that the alias-data in the Dock file was enough so that if I clicked one of the invalid apps, it would launch correctly, and the Dock would update the pathname to Whac/B.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.