macOS Setup with a Bash Script
Setting up a new macOS machine can be both fun and cumbersome. It usually involves a combination of installations, configurations, and fine-tunings that can consume hours of your time. In this blog post, I’ll introduce you to a handy Bash script that will do most of the heavy lifting for you. From installing essential Homebrew packages to setting up developer tools and productivity apps, this script will have you up and running in no time.
Prerequisites
Before running the script, make sure:
- You are not running the script as a root user.
- You have an internet connection for downloading packages and apps.
How to Use the Script
- Save the provided Bash script to a file, e.g.,
setup_uv.sh. - Open your terminal.
- Navigate to the folder containing
setup_uv.sh. - Make the script executable with
chmod +x setup_uv.sh. - Run the script using
./setup_uv.sh.
What Does the Script Do?
Here is a brief overview of what the script installs or configures:
System and Developer Tools:
- Xcode Command Line Tools: Essential tools for compiling and debugging from the terminal.
- Homebrew: The package manager for macOS (or Linux).
- Zsh Completions: Adds additional completion definitions for Zsh.
- ssh-copy-id: A script that installs an SSH key on a server as an authorized key.
- wget: A free utility for non-interactive downloading of files from the web.
- git: Distributed version control system.
- uv: A fast Python package installer and resolver, written in Rust.
- openssl, readline, sqlite3, xz, zlib: Libraries needed for various packages.
- syncthing: Open-source continuous file synchronization program.
Apps:
- Tabby, Fig, Visual Studio Code, Docker: Developer tools.
- 1Password, Shadow: Security apps.
- Superhuman, Slack, Keybase: Communication apps.
- VMware Fusion: Virtualization software.
- Obsidian, HiddenBar, Numi, Arc, Charles, Itsycal: Productivity apps.
- Raycast, Insomnia: API and shell utilities.
- AltServer: Alternative app store for non-jailbroken iOS devices.
- Adobe Creative Cloud, Elgato Stream Deck: Creative and streaming apps.
Other Configurations:
- Makes the
~/Libraryfolder visible. - Installs the latest Python version using
uv. - Upgrades
pipandsetuptools. - Installs
virtualenvfor Python. - Sets up directories and configurations for
pip. - Installs
Oh My Zshfor a better shell experience. - Adds a global
pipfunction (gpip) to your Zsh configuration.
Error Logging:
The script captures all output and timestamps it, storing this information in a setup_uv.log file. This can be invaluable for debugging or understanding what the script has done.
Noteworthy Points
- The script checks if an application or package is already installed before attempting installation.
- The script does not run as a root user. It exits if attempted.
- Some apps like
Syncthing,Superhuman,ChatGPT, andRocket Promay require post-installation setup. You will see a message in the terminal reminding you of this. - Remember to look at the
setup_uv.logfile for any post-installation tasks.
Conclusion
Automating your macOS setup can save you hours of manual work, leaving you with a ready-to-use machine stocked with essential tools and apps. You can further customize this script according to your personal needs, making your next macOS setup a breeze.
Script
#!/bin/bash
{
# Check for root access
if [ "$EUID" -eq 0 ]; then
echo "Please do not run as root"
exit 1
fi
# Install Xcode Command Line Tools
echo "Installing Xcode Command Line Tools..."
xcode-select --install
# Make the Library folder visible
echo "Making the ~/Library folder visible..."
chflags nohidden ~/Library
# Check if Homebrew is already installed
if ! command -v brew &> /dev/null; then
echo "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
else
echo "Homebrew already installed."
fi
# Update Homebrew
echo "Updating Homebrew..."
brew update
# Install useful packages
echo "Installing useful Homebrew packages..."
brew install neovim zsh-completions ssh-copy-id wget git uv openssl readline sqlite3 xz zlib syncthing
# Install Cask applications
echo "Installing Cask applications..."
apps=("tabby" "visual-studio-code" "docker" "1password" "shadow" "superhuman" "utm" "slack" "keybase" "hiddenbar" "numi" "arc" "charles" "itsycal" "raycast" "insomnia" "altserver" "ticktick" "alttab", "tailscale" "snagit" "rocket" "rectangle")
for app in "${apps[@]}"; do
if ! brew list --cask "$app" &>/dev/null; then
brew install --cask "$app"
else
echo "$app is already installed."
fi
done
# Install Python through uv
echo "Installing Python..."
uv python install
export PATH="$HOME/.uv/bin:$PATH"
echo -e "\n# Add uv to PATH\nexport PATH=\"$HOME/.uv/bin:$PATH\"" >> ~/.zshrc
python --version
# Upgrade pip and setuptools
echo "Upgrading Pip and Setuptools..."
uv pip install --upgrade pip setuptools
# Install virtualenv
echo "Installing Virtualenv..."
uv pip install virtualenv
# Directory setup
echo "Creating directories..."
mkdir -p ~/.config/pip
# Configure pip
echo "Configuring Pip..."
echo -e "[install]\nrequire-virtualenv = true\n\n[uninstall]\nrequire-virtualenv = true" > ~/.config/pip/pip.conf
# Install Oh My Zsh
echo "Installing Oh My Zsh..."
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
# Add global pip function to Zsh configuration
echo "Adding gpip() to Zsh configuration..."
echo -e "\n# Global pip function\ngpip(){\n PIP_REQUIRE_VIRTUALENV=\"0\" python -m pip \"\$@\"\n}" >> ~/.zshrc
# Add Zsh Completions to .zshrc
echo "Adding Zsh Completions to Zsh configuration..."
echo -e "\n# Zsh Completions\nif type brew &>/dev/null; then\n FPATH=\$(brew --prefix)/share/zsh-completions:\$FPATH\n autoload -Uz compinit\n compinit\nfi" >> ~/.zshrc
# Reload Zshrc
echo "Reloading Zsh configuration..."
source ~/.zshrc
} 2>&1 | while read -r line; do echo "[$(date +'%Y-%m-%d %H:%M:%S')] $line"; done | tee setup_uv.log
# Finish
echo "Setup complete!"
echo "Setup Syncthing, Superhuman"
echo "Look at the setup_uv.log file for post brew tasks"