DEV Community

Cover image for run.sh Diaries #2: The Bash Behind the Bootstrap
LazyDoomSlayer
LazyDoomSlayer

Posted on

run.sh Diaries #2: The Bash Behind the Bootstrap

TL;DR

In this post, I’ll walk through the internal logic of how my WSL bootstrap works and let’s focus on run.sh, utils.sh, and packages.conf. You’ll learn how I made the setup modular, safe to re-run, and easy to extend.

The Big Picture

In Part 1, I talked about why I built this and now let’s explore how it works.

At the heart of it is a simple philosophy:

Don’t repeat yourself.

Don’t install what’s already there.

Keep everything scriptable and modular.

The setup revolves around three key components:

  1. run.sh – the orchestrator
  2. utils.sh – helper functions
  3. packages.conf – what to install

Let’s break each down.

1. run.sh – The Orchestrator

This script is the entry point of the whole bootstrap.

Responsibilities:

  • Define the list of setup scripts to run
  • Execute them one by one
  • Log their progress
  • Fail fast if something breaks

Structure:

readonly SCRIPTS=(
  "node-setup.sh"
  "rust-setup.sh"
  "docker-setup.sh"
  "lazygit-setup.sh"
  "python-setup.sh"
  "zoxide-setup.sh"
  "tmux-config-setup.sh"
  "tpm-setup.sh"
  "nvim-setup.sh"
)
Enter fullscreen mode Exit fullscreen mode

Each script is passed into the run_script() function from utils.sh, which:

  • Checks if the file exists
  • Makes it executable
  • Runs it and logs its completion

2. utils.sh – The Bash Toolkit

This file contains reusable helpers that keep the logic clean and DRY.

Key Functions:

is_installed_apt / is_installed_snap

Check if a package is already installed before trying to install it.

  dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q "install ok installed"
Enter fullscreen mode Exit fullscreen mode

install_apt_packages / install_snap_packages

Take a list of packages, filter out the ones already installed, and install only what’s needed.

Includes logic to:

  • Run apt-get update only if required
  • Handle Snap not being installed
  • Try both normal and -classic Snap installs

die

A simple exit-on-error function to fail cleanly and loudly.

die() {
  echo "ERROR: $*" >&2
  exit 1
}
Enter fullscreen mode Exit fullscreen mode

In the future, I plan to add features like color-coded logging, verbosity levels, timestamps, and WSL detection. But for now, the current setup does exactly what I need: simple, readable, and effective.

3. packages.conf – Centralized Package List

This is where all core APT and Snap packages are defined and grouped by category for clarity.

Example:

SYSTEM_UTILS_APT=(
  wget curl fzf build-essential fd-find ripgrep
)

DEV_TOOLS_SNAP=(
  nvim
)
Enter fullscreen mode Exit fullscreen mode

Each package list is passed into the installer functions in utils.sh.

This structure makes it easy to:

  • Add/remove tools cleanly
  • See what’s included at a glance
  • Extend with new categories later

Why This Structure Works

  • Modularity: each setup script does one job
  • Reusability: helpers prevent duplication
  • Clarity: it’s easy to understand what gets installed and how
  • Safety: checks prevent reinstalling or breaking existing tools

Want to Try It?

⚠️Security Reminder

Never run scripts from the internet — including mine — without reading and understanding them first.
Even if you trust the source, it's good practice to inspect any Bash script before executing it.

I care about security too and my WSL bootstrap project is open source, transparent, and written to be as readable and modular as possible. Fork it, inspect it, tweak it.

git clone https://github.com/LazyDoomSlayer/os-bootstraps
cd os-bootstraps/ubuntu
chmod +x run.sh
./run.sh
Enter fullscreen mode Exit fullscreen mode

Install time: ~5 minutes on a VM with 8GB RAM, 8-core CPU, and 50Mbps connection.

First-time runs may take longer if your system hasn’t been updated with apt-get update && upgrade.

Everything else happens automatically. Grab a coffee. ☕

What’s Next: The CLI Stack

In Part 3, I’ll show you the terminal tools I bootstrap like tmux, zoxide, lazygit, and neovim and how they fit into my daily workflow.

Want to go full terminal-first? This next part is for you.

Top comments (0)