Created
November 25, 2025 22:51
-
-
Save bgrewell/23a7ba4adf742403c98d607c808f080f to your computer and use it in GitHub Desktop.
Bootstrap Desktop is my custom install script for setting up Linux environments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # ================================================================ | |
| # Config: edit this section to match your preferences | |
| # ================================================================ | |
| # --- APT packages ------------------------------------------------ | |
| COMMON_APT_PACKAGES=( | |
| git | |
| curl | |
| wget | |
| htop | |
| tmux | |
| build-essential | |
| python3 | |
| python3-pip | |
| ca-certificates | |
| ) | |
| UBUNTU_APT_PACKAGES=( | |
| gnome-tweaks | |
| fonts-firacode | |
| ) | |
| KALI_APT_PACKAGES=( | |
| kali-tools-top10 | |
| ) | |
| # --- Snap packages (optional) ----------------------------------- | |
| # Each entry is literally appended to `snap install`, so: | |
| # "code --classic" => snap install code --classic | |
| SNAP_PACKAGES=( | |
| # "code --classic" | |
| ) | |
| # --- Custom installers (git clone, curl | bash, etc.) ------------ | |
| custom_installers() { | |
| # Example: install Starship prompt | |
| # if ! command -v starship &>/dev/null; then | |
| # curl -sS https://starship.rs/install.sh | sh -s -- -y | |
| # fi | |
| : | |
| } | |
| # --- PATH entries to ensure are present -------------------------- | |
| PATH_ENTRIES=( | |
| "$HOME/bin" | |
| "$HOME/.local/bin" | |
| ) | |
| # --- GNOME config ------------------------------------------------ | |
| # Favorites in the dock (GNOME Shell) | |
| GNOME_DOCK_FAVORITES=( | |
| "org.gnome.Nautilus.desktop" | |
| "org.gnome.Terminal.desktop" | |
| "firefox.desktop" | |
| # "code.desktop" | |
| ) | |
| # Background image – must exist for this to work | |
| GNOME_BACKGROUND_IMAGE="$HOME/Pictures/wallpapers/default-bg.jpg" | |
| # Optional: dconf dump file for GNOME Terminal profiles | |
| # You can create one with: | |
| # dconf dump /org/gnome/terminal/legacy/profiles:/ > gnome-terminal.dconf | |
| GNOME_TERMINAL_DCONF_FILE="$HOME/.config/gnome-terminal.dconf" | |
| # ================================================================ | |
| # Helpers | |
| # ================================================================ | |
| log() { | |
| printf '[*] %s\n' "$*" >&2 | |
| } | |
| warn() { | |
| printf '[!] %s\n' "$*" >&2 | |
| } | |
| die() { | |
| printf '[X] %s\n' "$*" >&2 | |
| exit 1 | |
| } | |
| # sudo wrapper – override with SUDO= if you want | |
| SUDO="${SUDO:-sudo}" | |
| detect_distro() { | |
| if [[ -r /etc/os-release ]]; then | |
| # shellcheck disable=SC1091 | |
| . /etc/os-release | |
| echo "${ID:-unknown}" | |
| else | |
| echo "unknown" | |
| fi | |
| } | |
| ensure_path_entry_in_shell_rc() { | |
| local entry="$1" | |
| local shell_rc="$2" | |
| [[ -f "$shell_rc" ]] || return 0 | |
| local marker="# BEGIN bootstrap PATH $entry" | |
| if grep -Fq "$marker" "$shell_rc"; then | |
| return 0 | |
| fi | |
| log "Adding PATH entry '$entry' to $shell_rc" | |
| { | |
| echo "" | |
| echo "$marker" | |
| echo "if [[ \":\$PATH:\" != *\":$entry:\"* ]]; then" | |
| echo " export PATH=\"$entry:\$PATH\"" | |
| echo "fi" | |
| echo "# END bootstrap PATH $entry" | |
| } >>"$shell_rc" | |
| } | |
| # ================================================================ | |
| # Tasks | |
| # ================================================================ | |
| install_packages() { | |
| local distro pkgs=() | |
| distro="$(detect_distro)" | |
| if ! command -v apt-get &>/dev/null; then | |
| die "apt-get not found; this script currently expects an APT-based distro." | |
| fi | |
| pkgs+=("${COMMON_APT_PACKAGES[@]}") | |
| case "$distro" in | |
| ubuntu) | |
| pkgs+=("${UBUNTU_APT_PACKAGES[@]}") | |
| ;; | |
| kali) | |
| pkgs+=("${KALI_APT_PACKAGES[@]}") | |
| ;; | |
| *) | |
| warn "Unknown distro '$distro'; installing only COMMON_APT_PACKAGES." | |
| ;; | |
| esac | |
| if ((${#pkgs[@]} > 0)); then | |
| log "Updating APT package index" | |
| $SUDO apt-get update -y | |
| log "Installing APT packages: ${pkgs[*]}" | |
| $SUDO apt-get install -y "${pkgs[@]}" | |
| else | |
| log "No APT packages configured to install." | |
| fi | |
| if ((${#SNAP_PACKAGES[@]} > 0)); then | |
| if ! command -v snap &>/dev/null; then | |
| warn "snap not found; skipping Snap packages." | |
| else | |
| for snap_spec in "${SNAP_PACKAGES[@]}"; do | |
| log "Installing Snap package: snap install ${snap_spec}" | |
| # word splitting intentional here | |
| snap install ${snap_spec} | |
| done | |
| fi | |
| fi | |
| } | |
| update_paths() { | |
| for entry in "${PATH_ENTRIES[@]}"; do | |
| [[ -d "$entry" ]] || mkdir -p "$entry" | |
| ensure_path_entry_in_shell_rc "$entry" "$HOME/.bashrc" | |
| ensure_path_entry_in_shell_rc "$entry" "$HOME/.zshrc" | |
| done | |
| log "PATH modifications added. Open a new shell to pick them up." | |
| } | |
| configure_gnome() { | |
| if ! command -v gsettings &>/dev/null; then | |
| warn "gsettings not found; skipping GNOME configuration." | |
| return | |
| fi | |
| local desktop="${XDG_CURRENT_DESKTOP:-}" | |
| if [[ "$desktop" != *GNOME* && "$desktop" != *gnome* ]]; then | |
| warn "XDG_CURRENT_DESKTOP does not look like GNOME ('$desktop'); continuing anyway." | |
| fi | |
| # Dock favorites | |
| if ((${#GNOME_DOCK_FAVORITES[@]} > 0)); then | |
| local favs | |
| printf -v favs "'%s', " "${GNOME_DOCK_FAVORITES[@]}" | |
| favs="[${favs%, }]" | |
| log "Setting GNOME Shell favorites to: $favs" | |
| gsettings set org.gnome.shell favorite-apps "$favs" || warn "Failed to set GNOME favorites." | |
| fi | |
| # Background | |
| if [[ -f "$GNOME_BACKGROUND_IMAGE" ]]; then | |
| local uri="file://$GNOME_BACKGROUND_IMAGE" | |
| log "Setting GNOME background to: $uri" | |
| gsettings set org.gnome.desktop.background picture-uri "$uri" \ | |
| || warn "Failed to set picture-uri." | |
| # Some GNOME versions use picture-uri-dark as well | |
| gsettings set org.gnome.desktop.background picture-uri-dark "$uri" \ | |
| 2>/dev/null || true | |
| else | |
| warn "Background image not found at $GNOME_BACKGROUND_IMAGE; skipping background." | |
| fi | |
| # GNOME Terminal profiles via dconf dump | |
| if [[ -f "$GNOME_TERMINAL_DCONF_FILE" ]] && command -v dconf &>/dev/null; then | |
| log "Loading GNOME Terminal profile from $GNOME_TERMINAL_DCONF_FILE" | |
| dconf load /org/gnome/terminal/legacy/profiles:/ <"$GNOME_TERMINAL_DCONF_FILE" \ | |
| || warn "Failed to load GNOME Terminal dconf file." | |
| else | |
| warn "GNOME Terminal dconf file not found or dconf missing; skipping terminal profile import." | |
| fi | |
| # Example: tweak dock behavior if dash-to-dock is present | |
| if gsettings list-schemas | grep -q 'org.gnome.shell.extensions.dash-to-dock'; then | |
| log "Configuring dash-to-dock options" | |
| gsettings set org.gnome.shell.extensions.dash-to-dock dock-fixed true || true | |
| gsettings set org.gnome.shell.extensions.dash-to-dock click-action 'minimize' || true | |
| fi | |
| } | |
| run_custom_installers() { | |
| log "Running custom installers" | |
| custom_installers | |
| } | |
| # ================================================================ | |
| # Main | |
| # ================================================================ | |
| usage() { | |
| cat <<EOF | |
| Usage: $(basename "$0") [task ...] | |
| Tasks: | |
| packages Install packages (APT + optional Snap) | |
| paths Ensure PATH entries are present in shell rc files | |
| gnome Configure GNOME (dock, background, terminal, etc.) | |
| custom Run custom installers (curl/git/etc.) | |
| all Run all of the above | |
| If no task is given, 'all' is assumed. | |
| EOF | |
| } | |
| main() { | |
| if [[ "${1-}" == "-h" || "${1-}" == "--help" ]]; then | |
| usage | |
| exit 0 | |
| fi | |
| local tasks=("$@") | |
| if ((${#tasks[@]} == 0)); then | |
| tasks=(all) | |
| fi | |
| for task in "${tasks[@]}"; do | |
| case "$task" in | |
| packages) | |
| install_packages | |
| ;; | |
| paths) | |
| update_paths | |
| ;; | |
| gnome) | |
| configure_gnome | |
| ;; | |
| custom) | |
| run_custom_installers | |
| ;; | |
| all) | |
| install_packages | |
| update_paths | |
| configure_gnome | |
| run_custom_installers | |
| ;; | |
| *) | |
| warn "Unknown task '$task'" | |
| usage | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| log "Done." | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment