![]()
I have allot of different software tools on my mac that I need to keep up to date (brew, kubectl-krew, tldr, npm, cargo, pipx, gup, helm, mas) all with their own package managers.
I have a zsh script that I run to keep all of my software tools up to date.
Add the following to your .zshrc file or similar, and invoke it with update_everything in your terminal:
function update_everything() {
local failed=()
run_step() {
local label="$1"
shift
local cmd=("$@")
local error_output
local exit_code
local tmp_err
# Create temporary file for stderr capture
tmp_err=$(mktemp)
# Run command, capturing stderr to temp file
if "${cmd[@]}" 2>"$tmp_err" >/dev/null; then
echo ">>> [$label] ✅ success"
rm -f "$tmp_err"
else
exit_code=$?
error_output=$(cat "$tmp_err" 2>/dev/null)
rm -f "$tmp_err"
echo ">>> [$label] ❌ failed (exit code: $exit_code)"
echo " └─ Command: ${cmd[*]}"
if [[ -n "$error_output" ]]; then
echo " └─ Error output:"
echo "$error_output" | sed 's/^/ │ /'
else
echo " └─ (No error output captured)"
fi
failed+=("$label")
fi
}
setopt local_options
unsetopt monitor
{
run_step "brew" bash -c 'brew update && brew upgrade && brew cleanup --prune=all && rm -rf "$(brew --prefix)/var/homebrew/locks"'
} &
{ run_step "kubectl-krew" bash -c 'kubectl krew update && kubectl krew upgrade'; } &
{ run_step "tldr" tldr --update; } &
{ run_step "npm" npm update -g; } &
{ run_step "cargo" cargo install-update -a; } &
{ run_step "pipx" pipx upgrade-all; } &
{ run_step "gup" gup update; } &
{ run_step "helm" helm repo update; } &
{
run_step "mas" bash -c "
mapfile -t mas_apps < <(mas outdated | awk '{\$1=\"\"; sub(/^ /,\"\"); sub(/ \\([0-9.]+\\)\$/,\"\"); print}')
relaunch_apps=()
for app in \"\${mas_apps[@]}\"; do
if pgrep -fx \"\$app\" >/dev/null || pgrep -f \"/Applications/\$app.app\" >/dev/null; then
osascript -e \"quit app \\\"\$app\\\"\" || true
relaunch_apps+=(\"\$app\")
fi
done
mas upgrade
for app in \"\${relaunch_apps[@]}\"; do
open -a \"\$app\" || true
done
"
} &
wait
echo
if (( ${#failed[@]} )); then
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "❌ Summary: ${#failed[@]} step(s) failed"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
for f in "${failed[@]}"; do
echo " • $f"
done
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
else
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ All updates completed successfully 🎉"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
fi
}
Each utility will be run in a separate background process (run_step), and the script will wait for all of them to complete before displaying the results.