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:

  1. You are not running the script as a root user.
  2. You have an internet connection for downloading packages and apps.

How to Use the Script

  1. Save the provided Bash script to a file, e.g., setup_uv.sh.
  2. Open your terminal.
  3. Navigate to the folder containing setup_uv.sh.
  4. Make the script executable with chmod +x setup_uv.sh.
  5. 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 ~/Library folder visible.
  • Installs the latest Python version using uv.
  • Upgrades pip and setuptools.
  • Installs virtualenv for Python.
  • Sets up directories and configurations for pip.
  • Installs Oh My Zsh for a better shell experience.
  • Adds a global pip function (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, and Rocket Pro may require post-installation setup. You will see a message in the terminal reminding you of this.
  • Remember to look at the setup_uv.log file 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"