Skip to content

Instantly share code, notes, and snippets.

@jeremy-code
Created April 11, 2025 21:35
Show Gist options
  • Save jeremy-code/c337ae97fc617bc6f6e325d3b4a85cb0 to your computer and use it in GitHub Desktop.
Save jeremy-code/c337ae97fc617bc6f6e325d3b4a85cb0 to your computer and use it in GitHub Desktop.
Watch output of `defaults read`

I'm experimenting with matching changes made in the System Settings app with the output of defaults read, and I made this quick script for help with that.

It's not perfect -- namely, defaults read outputs in OpenStep format which is very much not machine parseable, but the alternative is using defaults export which requires you to list a domain, which would be much more complicated (though not impossible using defaults domains).

You will probably need to add more or less ignored_lines depending on what apps you use.

#!/bin/zsh
readonly -i INTERVAL_IN_SECONDS=2
echo "Watching defaults..."
echo "Polling every ${INTERVAL_IN_SECONDS} seconds..."
echo "-------------------------------"
ignored_lines=(
"OwnedDeviceLastPublishDate" # com.apple.icloud.searchpartyuseragent
"_DKThrottledActivityLast" # knowledge-agent
"PLSyndicationLastUpdateDate" # com.apple.photolibraryd
"HashManager-" # com.apple.sharingd
"AMSActivityObserverDateLastCheckedIn" # com.apple.amsengagementd
"AMSMetricsIdentifierDateLastSynced"
"lastRefreshDate" # com.apple.UsageTrackingAgent
"AppleInputSourceUpdateTime" # com.apple.HIToolbox
"MTAlarmModifiedDate" # com.apple.mobiletimerd
"world = " # com.apple.chronod > lastKnownTimes
"com.apple.osanalytics.stability-monitor" # com.apple.xpc.activity2
"com.apple.osanalytics.submissions.submit"
"com.apple.osanalytics.submissions.submit-permissive"
"com.apple.searchpartyd.OwnDevicePublish"
)
ignored_lines=(
${ignored_lines/#/--ignore-matching-lines=}
)
while true; do
prev_defaults=$(defaults read)
sleep ${INTERVAL_IN_SECONDS}
curr_defaults=$(defaults read)
if [[ "${prev_defaults}" != "${curr_defaults}" ]]; then
diff --unified "${ignored_lines[@]}" <(echo "${prev_defaults}") <(echo "${curr_defaults}")
fi
done
@jeremy-code
Copy link
Author

jeremy-code commented Apr 11, 2025

Here's the start of a version that polls based on domain. I need to think of a way to parse XML better, but I think this is probably a more viable strategy than the above

#!/bin/zsh
readonly -i INTERVAL_IN_SECONDS=2

readonly DOMAINS_TO_IGNORE=(
  com.apple.xpc.activity2
)

echo "Polling defaults every ${INTERVAL_IN_SECONDS} seconds..."

domains=( ${(ps:, :)$(defaults domains)} )

declare -A domainToPlist

for domain in "${domains[@]}"; do
  if (( ! $DOMAINS_TO_IGNORE[(Ie)$domain])); then
    domainToPlist[$domain]=$(defaults export "$domain" -)
  fi
done

while true; do
  sleep ${INTERVAL_IN_SECONDS}

  for domain prevPlist in "${(@kv)domainToPlist}"; do
    currentPlist=$(defaults export "$domain" -)
    if [[ "${prevPlist}" != "$currentPlist" ]]; then
      echo "Changes detected in $domain"
      diff <(echo "${prevPlist}") <(echo "$currentPlist")
      domainToPlist[$domain]="$currentPlist"
    fi
  done
done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment