Skip to content

Instantly share code, notes, and snippets.

@olafgeibig
Last active November 5, 2025 15:11
Show Gist options
  • Select an option

  • Save olafgeibig/f632e51da04397a3174caf4c711e6382 to your computer and use it in GitHub Desktop.

Select an option

Save olafgeibig/f632e51da04397a3174caf4c711e6382 to your computer and use it in GitHub Desktop.
Mac Update Script

This script updates the most important software installations on my Mac. It covers updates from:

  • Brew
  • Apple AppStore
  • XCode
  • MacOS
  • globally installed packages from npm and uv

After the updates it performs a clean-up. The script can update single sources but without any argument it updates everything, see update.sh --help

I usually run it every couple of days but it is recommeded to check the console output for errors and warnings. Some brew update warnings mean that you need to overwrite the brew link of a package or it is not correctly installed anymore, e.g. brew link --overwrite node

#!/bin/zsh
# filepath: ~/.local/bin/update.sh
# Description: Script to update various software on macOS
# Date: June 6, 2025
# Color definitions for better output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Function to print section headers
print_header() {
echo -e "\n${BLUE}==== $1 ====${NC}\n"
}
# Function to print success messages
print_success() {
echo -e "${GREEN}$1${NC}"
}
# Function to print error messages
print_error() {
echo -e "${RED}$1${NC}"
}
# Function to print warnings
print_warning() {
echo -e "${YELLOW}! $1${NC}"
}
# Function to update Homebrew and its packages
update_brew() {
print_header "Updating Homebrew packages"
# Check if brew is installed
if ! command -v brew &> /dev/null; then
print_error "Homebrew is not installed"
return 1
fi
# Update brew itself
echo "Updating Homebrew..."
brew update
# Upgrade all packages
echo "Upgrading Homebrew packages..."
brew upgrade
# Cleanup old versions
echo "Cleaning up old versions..."
brew cleanup
print_success "Homebrew update completed"
}
# Function to update npm global packages
update_npm() {
print_header "Updating npm global packages"
# Check if npm is installed
if ! command -v npm &> /dev/null; then
print_error "npm is not installed"
return 1
fi
echo "Updating npm itself..."
brew upgrade npm
echo "Updating global npm packages..."
npm update -g
print_success "npm update completed"
}
# Function to update uv global packages
update_uv() {
print_header "Updating uv global packages"
# Check if uv is installed
if ! command -v uv &> /dev/null; then
print_error "uv is not installed"
return 1
fi
echo "Updating uv itself..."
brew upgrade uv
echo "Updating global packages managed by uv..."
# Note: The exact command might vary based on uv's API
# This is a placeholder - replace with the correct command if different
# uv pip install --upgrade --global $(uv pip list --global | tail -n +3 | cut -d ' ' -f 1)
uv tool upgrade --all
print_success "uv update completed"
}
# Function to update macOS App Store apps
update_appstore() {
print_header "Updating App Store applications"
# Check if mas-cli is installed (Mac App Store command line interface)
if ! command -v mas &> /dev/null; then
print_warning "mas-cli is not installed. Cannot update App Store apps from the command line."
print_warning "To install mas: brew install mas"
return 1
else
echo "Updating App Store applications..."
mas upgrade
print_success "App Store updates completed"
fi
}
# Function to update Xcode
update_xcode() {
print_header "Updating Xcode"
# Check if xcode-select is installed
if ! command -v xcode-select &> /dev/null; then
print_error "Xcode command line tools are not installed"
return 1
fi
echo "Checking for Xcode updates..."
# For Xcode command line tools
softwareupdate --list | grep "Command Line Tools"
if [ $? -eq 0 ]; then
echo "Updating Xcode command line tools..."
softwareupdate --install --all --agree-to-license
fi
# For full Xcode, we can check if it's installed first
if [ -d "/Applications/Xcode.app" ]; then
print_warning "Full Xcode is installed."
print_warning "Please update Xcode manually through the App Store."
# mas can be used to update Xcode if mas-cli is installed
if command -v mas &> /dev/null; then
XCODE_ID=$(mas list | grep Xcode | awk '{print $1}')
if [ ! -z "$XCODE_ID" ]; then
echo "Attempting to update Xcode via mas-cli..."
mas upgrade $XCODE_ID
fi
fi
fi
print_success "Xcode update check completed"
}
# Function to update system software
update_system() {
print_header "Checking for macOS updates"
echo "Checking for system updates..."
softwareupdate --list
print_warning "To install system updates, run: softwareupdate --install --all --agree-to-license"
print_warning "Note: System updates may require a restart"
}
# Function to run all updates
update_all() {
update_brew
update_npm
update_uv
update_appstore
update_xcode
update_system
print_header "All updates completed!"
}
cleanup() {
print_header "Cleaning up temporary files"
npm cache clean --force
uv cache prune
brew cleanup
print_success "Cleanup completed"
}
# Show help message
show_help() {
echo "Usage: update.sh [OPTIONS]"
echo "Update various software on your macOS system."
echo ""
echo "Options:"
echo " --all Update everything (default if no option is provided)"
echo " --brew Update Homebrew and its packages"
echo " --npm Update npm and global npm packages"
echo " --uv Update uv and global uv packages"
echo " --appstore Update App Store applications (requires mas-cli)"
echo " --xcode Update Xcode and command line tools"
echo " --system Check for macOS system updates"
echo " --cleanup Clean up cached and temporary files"
echo " --help Display this help message"
}
# Main script execution
# If no arguments, run all updates
if [ $# -eq 0 ]; then
update_all
exit 0
fi
# Process command line arguments
while [ $# -gt 0 ]; do
case "$1" in
--all)
update_all
;;
--brew)
update_brew
;;
--npm)
update_npm
;;
--uv)
update_uv
;;
--appstore)
update_appstore
;;
--xcode)
update_xcode
;;
--system)
update_system
;;
--cleanup)
cleanup
;;
--help)
show_help
;;
*)
print_error "Unknown option: $1"
show_help
exit 1
;;
esac
shift
done
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment