Configuration Management

This chapter demonstrates how to use bashrs to manage shell configuration files (.bashrc, .bash_profile, .zshrc), transforming messy, non-idempotent configurations into clean, deterministic, maintainable config files.

Overview: Why Configuration Management Matters

Shell configuration files are critical infrastructure:

  • Loaded on every shell start: Bugs multiply across sessions
  • Affects all shell commands: PATH errors break everything
  • Hard to debug: Silent failures, subtle bugs
  • Machine-specific drift: Works on laptop, breaks on server
  • Accumulates cruft: Years of copy-paste, duplicate settings

Common problems:

  • Non-idempotent: Re-sourcing breaks configuration
  • PATH pollution: Duplicates slow shell startup
  • Unquoted variables: Injection vulnerabilities
  • Duplicate aliases: Conflicting definitions
  • Non-deterministic: Different behavior on each machine

bashrs solves these problems by analyzing, linting, and purifying shell configuration files.


The Problem: Messy .bashrc

Example: Problematic Configuration File

 ~/.bashrc - PROBLEMATIC configuration

 ❌ Non-idempotent: PATH duplicates on every source
export PATH="$HOME/.local/bin:$PATH"
export PATH="/usr/local/go/bin:$PATH"
export PATH="$HOME/bin:$PATH"

 ❌ Unquoted variables (SC2086)
export GOPATH=$HOME/go
export EDITOR=vim

 ❌ Duplicate alias definitions
alias ll="ls -la"
alias ll="ls -lah"  # Overwrites previous definition

 ❌ Non-idempotent: Appends on every source
export HISTSIZE=10000
export HISTSIZE=$((HISTSIZE + 1000))

 ❌ Non-deterministic: Uses $RANDOM
export SESSION_ID=$RANDOM

 ❌ Command substitution without quoting
export HOSTNAME=$(hostname)
export USER_HOME=$(eval echo ~$USER)

 ❌ Conditional with unquoted variables
if [ -d $HOME/.vim ]; then
    export VIM_CONFIG=$HOME/.vim
fi

 ❌ Function with non-idempotent operations
setup_env() {
    mkdir ~/.config/myapp
    ln -s ~/.config/myapp/config.yml ~/myapp.yml
}

 ❌ Source files without checking existence
source ~/.bash_aliases
source ~/.bash_functions

Issues Detected by bashrs

Running bashrs config analyze ~/.bashrc:

~/.bashrc:4:14: CONFIG-001 [Error] Non-idempotent PATH append
  export PATH="$HOME/.local/bin:$PATH"
  Fix: Use PATH deduplication function

~/.bashrc:5:14: CONFIG-001 [Error] Non-idempotent PATH append
  export PATH="/usr/local/go/bin:$PATH"
  Fix: Use PATH deduplication function

~/.bashrc:6:14: CONFIG-001 [Error] Non-idempotent PATH append
  export PATH="$HOME/bin:$PATH"
  Fix: Use PATH deduplication function

~/.bashrc:9:15: CONFIG-002 [Error] Unquoted variable in export
  export GOPATH=$HOME/go
  Fix: Quote variable: export GOPATH="$HOME/go"

~/.bashrc:10:15: CONFIG-002 [Error] Unquoted variable in export
  export EDITOR=vim
  Fix: Quote value: export EDITOR="vim"

~/.bashrc:13:1: CONFIG-003 [Warning] Duplicate alias definition
  alias ll="ls -la"
  Note: Redefined on line 14

~/.bashrc:14:1: CONFIG-003 [Warning] Duplicate alias definition
  alias ll="ls -lah"
  Fix: Remove duplicate, keep only one definition

~/.bashrc:17:17: CONFIG-004 [Error] Non-idempotent variable modification
  export HISTSIZE=$((HISTSIZE + 1000))
  Fix: Set to fixed value: export HISTSIZE=11000

~/.bashrc:20:18: DET001 [Error] Non-deterministic: $RANDOM
  export SESSION_ID=$RANDOM
  Fix: Use fixed value or configuration parameter

~/.bashrc:23:17: CONFIG-002 [Error] Unquoted command substitution
  export HOSTNAME=$(hostname)
  Fix: Quote: export HOSTNAME="$(hostname)"

~/.bashrc:24:18: SEC001 [Critical] eval usage
  export USER_HOME=$(eval echo ~$USER)
  Fix: Use $HOME directly or quote properly

~/.bashrc:27:9: CONFIG-002 [Error] Unquoted variable in condition
  if [ -d $HOME/.vim ]; then
  Fix: Quote: if [ -d "$HOME/.vim" ]; then

~/.bashrc:33:5: IDEM001 [Error] Non-idempotent: mkdir without -p
  mkdir ~/.config/myapp
  Fix: Use mkdir -p for idempotent operation

~/.bashrc:34:5: IDEM003 [Error] Non-idempotent: ln -s without cleanup
  ln -s ~/.config/myapp/config.yml ~/myapp.yml
  Fix: Remove existing link before creating

~/.bashrc:38:1: CONFIG-005 [Warning] Source without existence check
  source ~/.bash_aliases
  Fix: Check existence: [ -f ~/.bash_aliases ] && source ~/.bash_aliases

~/.bashrc:39:1: CONFIG-005 [Warning] Source without existence check
  source ~/.bash_functions
  Fix: Check existence: [ -f ~/.bash_functions ] && source ~/.bash_functions

17 issues found (13 errors, 4 warnings)

The Solution: Purified Configuration

Step 1: Lint the Configuration

 Analyze configuration for issues
bashrs config analyze ~/.bashrc

 Lint with detailed report
bashrs lint ~/.bashrc --format human

 Generate JSON report for tooling
bashrs lint ~/.bashrc --format json > bashrc-issues.json

Step 2: Purify the Configuration

 Purify configuration file
bashrs config purify ~/.bashrc --output ~/.bashrc.purified

 Show purification report
bashrs config purify ~/.bashrc --report

Purified Output

!/bin/sh
 ~/.bashrc - Purified by bashrs v6.32.1
 This is safe, deterministic, idempotent POSIX shell configuration

 ✅ Purified: Idempotent PATH management
 Function to add directory to PATH only if not already present
add_to_path() {
    _dir="$1"

     Check if directory exists and is not already in PATH
    if [ -d "${_dir}" ]; then
        case ":${PATH}:" in
            *":${_dir}:"*)
                 Already in PATH, skip
                ;;
            *)
                 Add to PATH
                export PATH="${_dir}:${PATH}"
                ;;
        esac
    fi
}

 ✅ Purified: Idempotent PATH configuration (no duplicates)
add_to_path "${HOME}/.local/bin"
add_to_path "/usr/local/go/bin"
add_to_path "${HOME}/bin"

 ✅ Purified: All variables properly quoted
export GOPATH="${HOME}/go"
export EDITOR="vim"

 ✅ Purified: Single alias definition (duplicate removed)
alias ll="ls -lah"

 ✅ Purified: Fixed value (was non-idempotent)
export HISTSIZE=11000
export HISTFILESIZE=20000

 ✅ Purified: Removed $RANDOM (non-deterministic)
 Use fixed session tracking if needed:
 export SESSION_ID="session-${USER}-$$"

 ✅ Purified: Quoted command substitution
export HOSTNAME="$(hostname)"

 ✅ Purified: Safe home directory reference (no eval)
export USER_HOME="${HOME}"

 ✅ Purified: Quoted variable in condition
if [ -d "${HOME}/.vim" ]; then
    export VIM_CONFIG="${HOME}/.vim"
fi

 ✅ Purified: Idempotent environment setup
setup_env() {
     Idempotent directory creation
    mkdir -p "${HOME}/.config/myapp" || return 1

     Idempotent symlink creation
    _link="${HOME}/myapp.yml"
    _target="${HOME}/.config/myapp/config.yml"

    if [ -e "${_link}" ] || [ -L "${_link}" ]; then
        rm -f "${_link}"
    fi

    ln -s "${_target}" "${_link}" || return 1

    return 0
}

 ✅ Purified: Safe sourcing with existence checks
if [ -f "${HOME}/.bash_aliases" ]; then
     shellcheck source=/dev/null
    . "${HOME}/.bash_aliases"
fi

if [ -f "${HOME}/.bash_functions" ]; then
     shellcheck source=/dev/null
    . "${HOME}/.bash_functions"
fi

 ✅ Purified: Proper error handling
set -u  # Error on undefined variables

 ✅ Purified: Shell-specific configurations
if [ -n "${BASH_VERSION:-}" ]; then
     Bash-specific settings
    shopt -s histappend
    shopt -s checkwinsize
fi

if [ -n "${ZSH_VERSION:-}" ]; then
     Zsh-specific settings
    setopt APPEND_HISTORY
    setopt SHARE_HISTORY
fi
```text

## Purification Report

```text
Configuration Purification Report
==================================

Issues Fixed: 17

CONFIG-001 (PATH deduplication): 3 fixes
  ✅ Implemented add_to_path() function
  ✅ Prevents duplicate PATH entries
  ✅ Checks directory existence before adding

CONFIG-002 (Quote variables): 6 fixes
  ✅ All variables quoted in exports
  ✅ Command substitutions quoted
  ✅ Variables quoted in conditionals

CONFIG-003 (Duplicate aliases): 2 fixes
  ✅ Removed duplicate alias definition
  ✅ Kept most recent definition

CONFIG-004 (Non-idempotent operations): 1 fix
  ✅ Replaced incremental HISTSIZE with fixed value

DET001 (Non-determinism): 1 fix
  ✅ Removed $RANDOM usage
  ✅ Added comment for deterministic alternative

SEC001 (eval usage): 1 fix
  ✅ Removed eval, use $HOME directly
  ✅ Eliminated code injection risk

IDEM001 (mkdir): 1 fix
  ✅ Changed to mkdir -p (idempotent)

IDEM003 (symlink): 1 fix
  ✅ Remove existing link before creating
  ✅ Safe to re-run

CONFIG-005 (Source without check): 2 fixes
  ✅ Added existence checks before sourcing
  ✅ Prevents errors when files missing

Quality Improvements:
  ✅ Deterministic: No $RANDOM, timestamps, or process IDs
  ✅ Idempotent: Safe to source multiple times
  ✅ POSIX Compliant: Works on sh, dash, ash, bash, zsh
  ✅ Secure: All variables quoted, no eval usage
  ✅ Maintainable: Clear structure, documented changes

Step-by-Step Workflow

1. Analyze Current Configuration

 Get overview of issues
bashrs config analyze ~/.bashrc

 Expected output:
Configuration Analysis: /home/user/.bashrc
========================================

Total Lines: 45
Shell Detected: bash
POSIX Compliant: No

Issue Summary:
  Errors: 13
  Warnings: 4
  Total: 17

Categories:
  CONFIG-001 (PATH issues): 3
  CONFIG-002 (Quoting): 6
  CONFIG-003 (Duplicates): 2
  CONFIG-004 (Non-idempotent): 1
  DET001 (Non-deterministic): 1
  SEC001 (Security): 1
  IDEM001 (mkdir): 1
  IDEM003 (symlink): 1
  CONFIG-005 (Sourcing): 2

Recommendations:
  1. Fix PATH management for idempotency
  2. Quote all variables
  3. Remove duplicate definitions
  4. Use fixed values instead of incremental
  5. Eliminate non-deterministic patterns

2. Lint for Specific Issues

 Lint for CONFIG issues only
bashrs lint ~/.bashrc --filter CONFIG

 Lint for security issues
bashrs lint ~/.bashrc --filter SEC

 Lint for determinism issues
bashrs lint ~/.bashrc --filter DET

 Lint with auto-fix suggestions
bashrs lint ~/.bashrc --fix

3. Purify Configuration

 Purify to idempotent configuration
bashrs config purify ~/.bashrc --output ~/.bashrc.purified

 Verify purified config
bashrs lint ~/.bashrc.purified

 Expected: 0 issues found

4. Test Idempotency

 Source configuration multiple times
 Should produce same result each time

 Test 1: Source once
source ~/.bashrc.purified
echo "$PATH" > /tmp/path1.txt

 Test 2: Source again
source ~/.bashrc.purified
echo "$PATH" > /tmp/path2.txt

 Test 3: Source third time
source ~/.bashrc.purified
echo "$PATH" > /tmp/path3.txt

 Verify identical
diff /tmp/path1.txt /tmp/path2.txt  # Should be identical
diff /tmp/path2.txt /tmp/path3.txt  # Should be identical

 Expected: No differences

5. Verify POSIX Compliance

 Check with shellcheck
shellcheck -s sh ~/.bashrc.purified

 Expected: No issues

6. Deploy Configuration

 Backup original
cp ~/.bashrc ~/.bashrc.backup

 Deploy purified version
cp ~/.bashrc.purified ~/.bashrc

 Test in new shell
bash --login

CONFIG Rules Examples

CONFIG-001: PATH Deduplication

Issue: Non-idempotent PATH appends

Bad: Duplicates on every source

export PATH="$HOME/.local/bin:$PATH"
export PATH="/usr/local/go/bin:$PATH"

 After sourcing 3 times:
 PATH=/usr/local/go/bin:/usr/local/go/bin:/usr/local/go/bin:$HOME/.local/bin:$HOME/.local/bin:$HOME/.local/bin:...

Good: Idempotent PATH management

add_to_path() {
    _dir="$1"
    if [ -d "${_dir}" ]; then
        case ":${PATH}:" in
            *":${_dir}:"*)
                 Already in PATH
                ;;
            *)
                export PATH="${_dir}:${PATH}"
                ;;
        esac
    fi
}

add_to_path "${HOME}/.local/bin"
add_to_path "/usr/local/go/bin"

 After sourcing 3 times:
 PATH=/usr/local/go/bin:$HOME/.local/bin:... (no duplicates)

Fix: bashrs automatically generates add_to_path() function

CONFIG-002: Quote Variables

Issue: Unquoted variables in exports

Bad: Injection risk, breaks on spaces

export GOPATH=$HOME/go
export PROJECT_DIR=$HOME/My Projects  # ❌ Breaks on space
export FILES=$(ls *.txt)  # ❌ Word splitting

Good: Properly quoted

export GOPATH="${HOME}/go"
export PROJECT_DIR="${HOME}/My Projects"  # ✅ Handles spaces
export FILES="$(ls *.txt)"  # ✅ No word splitting

Fix: bashrs adds quotes around all variable references

CONFIG-003: Duplicate Aliases

Issue: Conflicting alias definitions

Bad: Duplicate definitions (confusing)

alias ll="ls -la"
alias ll="ls -lah"  # Overwrites previous
alias grep="grep --color=auto"
alias grep="grep --color=always"  # Overwrites

Good: Single definition

alias ll="ls -lah"
alias grep="grep --color=auto"

Fix: bashrs removes duplicates, keeps last definition


Multi-Machine Configuration Strategies

Strategy 1: Modular Configuration

Split configuration into modular files:

 ~/.bashrc - Main configuration
!/bin/sh
 Purified by bashrs v6.32.1

 Source base configuration
if [ -f "${HOME}/.config/shell/base.sh" ]; then
    . "${HOME}/.config/shell/base.sh"
fi

 Source machine-specific configuration
if [ -f "${HOME}/.config/shell/$(hostname).sh" ]; then
    . "${HOME}/.config/shell/$(hostname).sh"
fi

 Source OS-specific configuration
case "$(uname -s)" in
    Linux)
        [ -f "${HOME}/.config/shell/linux.sh" ] && . "${HOME}/.config/shell/linux.sh"
        ;;
    Darwin)
        [ -f "${HOME}/.config/shell/macos.sh" ] && . "${HOME}/.config/shell/macos.sh"
        ;;
    FreeBSD)
        [ -f "${HOME}/.config/shell/freebsd.sh" ] && . "${HOME}/.config/shell/freebsd.sh"
        ;;
esac

 Source user-specific overrides
if [ -f "${HOME}/.config/shell/local.sh" ]; then
    . "${HOME}/.config/shell/local.sh"
fi

Files:

  • ~/.config/shell/base.sh - Common settings for all machines
  • ~/.config/shell/laptop.sh - Laptop-specific settings
  • ~/.config/shell/server.sh - Server-specific settings
  • ~/.config/shell/linux.sh - Linux-specific settings
  • ~/.config/shell/macos.sh - macOS-specific settings
  • ~/.config/shell/local.sh - User-specific overrides (gitignored)

Strategy 2: Conditional Blocks

Use conditionals for machine-specific settings:

 ~/.bashrc
!/bin/sh

 Base configuration (all machines)
export EDITOR="vim"
export PAGER="less"

 Machine-specific configuration
case "$(hostname)" in
    laptop)
         Laptop settings
        add_to_path "/opt/homebrew/bin"
        export DISPLAY=":0"
        ;;
    server*)
         Server settings
        add_to_path "/usr/local/sbin"
        export TMOUT=300  # Auto-logout after 5 minutes
        ;;
    workstation)
         Workstation settings
        add_to_path "/opt/cuda/bin"
        export GPU_ENABLED=1
        ;;
esac

 OS-specific configuration
if [ "$(uname -s)" = "Darwin" ]; then
     macOS settings
    export BASH_SILENCE_DEPRECATION_WARNING=1
    add_to_path "/usr/local/opt/coreutils/libexec/gnubin"
fi

if [ -f /etc/debian_version ]; then
     Debian/Ubuntu settings
    alias apt-update="sudo apt-get update && sudo apt-get upgrade"
fi

Strategy 3: Version Control

Store configuration in Git repository:

 Repository structure
dotfiles/
├── .bashrc
├── .bash_profile
├── .zshrc
├── .profile
├── config/
│   ├── shell/
│   │   ├── base.sh
│   │   ├── linux.sh
│   │   ├── macos.sh
│   │   └── local.sh.example
│   └── vim/
│       └── vimrc
├── scripts/
│   ├── install.sh
│   └── sync.sh
└── README.md

 Install script
!/bin/sh
 install.sh - Deploy dotfiles

set -eu

DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)"

 Backup existing configs
backup_config() {
    _file="$1"
    if [ -f "${HOME}/${_file}" ]; then
        echo "Backing up ${_file}..."
        cp "${HOME}/${_file}" "${HOME}/${_file}.backup.$(date +%Y%m%d)"
    fi
}

 Link configuration files
link_config() {
    _source="$1"
    _target="$2"

    echo "Linking ${_source} → ${_target}..."

     Remove existing link/file
    if [ -e "${_target}" ] || [ -L "${_target}" ]; then
        rm -f "${_target}"
    fi

     Create symlink
    ln -s "${_source}" "${_target}"
}

 Backup and link configs
backup_config ".bashrc"
backup_config ".bash_profile"
backup_config ".zshrc"

link_config "${DOTFILES_DIR}/.bashrc" "${HOME}/.bashrc"
link_config "${DOTFILES_DIR}/.bash_profile" "${HOME}/.bash_profile"
link_config "${DOTFILES_DIR}/.zshrc" "${HOME}/.zshrc"

 Create local config if doesn't exist
if [ ! -f "${HOME}/.config/shell/local.sh" ]; then
    mkdir -p "${HOME}/.config/shell"
    cp "${DOTFILES_DIR}/config/shell/local.sh.example" "${HOME}/.config/shell/local.sh"
fi

echo "✅ Dotfiles installed successfully!"

CI/CD Integration for Configuration Validation

GitHub Actions Workflow

# .github/workflows/validate-configs.yml
name: Validate Shell Configurations

on:
  push:
    paths:
      - '.bashrc'
      - '.bash_profile'
      - '.zshrc'
      - 'config/shell/**'
  pull_request:
    paths:
      - '.bashrc'
      - '.bash_profile'
      - '.zshrc'
      - 'config/shell/**'

jobs:
  validate-configs:
    name: Validate Configuration Files
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install bashrs
        run: |
          cargo install bashrs --version 6.32.1
          bashrs --version

      - name: Analyze configurations
        run: |
          echo "=== Analyzing .bashrc ==="
          bashrs config analyze .bashrc

          echo "=== Analyzing .bash_profile ==="
          bashrs config analyze .bash_profile

          echo "=== Analyzing config/shell/*.sh ==="
          for config in config/shell/*.sh; do
            echo "Analyzing $config..."
            bashrs config analyze "$config"
          done

      - name: Lint configurations
        run: |
          EXIT_CODE=0

          for config in .bashrc .bash_profile config/shell/*.sh; do
            if [ -f "$config" ]; then
              echo "Linting $config..."

              if ! bashrs lint "$config" --format human; then
                echo "❌ $config has issues"
                EXIT_CODE=1
              else
                echo "✅ $config passed"
              fi
            fi
          done

          exit $EXIT_CODE

      - name: Test idempotency
        run: |
          # Source config multiple times, verify PATH doesn't change
          bash -c '
            source .bashrc
            PATH1="$PATH"

            source .bashrc
            PATH2="$PATH"

            source .bashrc
            PATH3="$PATH"

            if [ "$PATH1" = "$PATH2" ] && [ "$PATH2" = "$PATH3" ]; then
              echo "✅ Configuration is idempotent"
              exit 0
            else
              echo "❌ Configuration is non-idempotent"
              echo "PATH after 1st source: $PATH1"
              echo "PATH after 2nd source: $PATH2"
              echo "PATH after 3rd source: $PATH3"
              exit 1
            fi
          '

      - name: Verify POSIX compliance
        run: |
          # Install shellcheck
          sudo apt-get update
          sudo apt-get install -y shellcheck

          # Check all shell files
          for config in .bashrc .bash_profile config/shell/*.sh; do
            if [ -f "$config" ]; then
              echo "Checking $config with shellcheck..."
              shellcheck -s sh "$config" || echo "⚠️ POSIX issues in $config"
            fi
          done

      - name: Generate quality report
        if: always()
        run: |
          mkdir -p reports/

          for config in .bashrc .bash_profile config/shell/*.sh; do
            if [ -f "$config" ]; then
              basename=$(basename "$config")
              bashrs lint "$config" --format json > "reports/${basename}.json"
            fi
          done

      - name: Upload reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: config-quality-reports
          path: reports/

Testing Configuration Files

Test 1: Idempotency Test

!/bin/sh
 test-idempotency.sh

set -eu

CONFIG="${1:-.bashrc}"

echo "Testing idempotency of $CONFIG..."

 Create test environment
TEST_DIR=$(mktemp -d)
trap 'rm -rf "$TEST_DIR"' EXIT

 Source config multiple times
(
    cd "$TEST_DIR"
    export HOME="$TEST_DIR"

     Source 3 times
    . "$CONFIG"
    PATH1="$PATH"

    . "$CONFIG"
    PATH2="$PATH"

    . "$CONFIG"
    PATH3="$PATH"

     Verify identical
    if [ "$PATH1" = "$PATH2" ] && [ "$PATH2" = "$PATH3" ]; then
        echo "✅ PASS: Configuration is idempotent"
        exit 0
    else
        echo "❌ FAIL: Configuration is non-idempotent"
        echo "  1st: $PATH1"
        echo "  2nd: $PATH2"
        echo "  3rd: $PATH3"
        exit 1
    fi
)

Test 2: POSIX Compliance Test

!/bin/sh
 test-posix-compliance.sh

set -eu

CONFIG="${1:-.bashrc}"

echo "Testing POSIX compliance of $CONFIG..."

 Check with shellcheck
if command -v shellcheck >/dev/null 2>&1; then
    if shellcheck -s sh "$CONFIG"; then
        echo "✅ PASS: POSIX compliant"
        exit 0
    else
        echo "❌ FAIL: POSIX violations detected"
        exit 1
    fi
else
    echo "⚠️ SKIP: shellcheck not installed"
    exit 0
fi

Test 3: Performance Test

!/bin/sh
 test-performance.sh

set -eu

CONFIG="${1:-.bashrc}"

echo "Testing startup performance of $CONFIG..."

 Measure time to source config
start=$(date +%s%N)

 Source config 10 times
i=0
while [ $i -lt 10 ]; do
    . "$CONFIG" >/dev/null 2>&1
    i=$((i + 1))
done

end=$(date +%s%N)

 Calculate average time
elapsed=$((end - start))
avg_ms=$((elapsed / 10000000))

echo "Average startup time: ${avg_ms}ms"

 Fail if too slow (>100ms)
if [ $avg_ms -gt 100 ]; then
    echo "❌ FAIL: Startup too slow (${avg_ms}ms > 100ms)"
    exit 1
else
    echo "✅ PASS: Startup time acceptable (${avg_ms}ms)"
    exit 0
fi

Best Practices

1. Version Control Your Configs

Bad: No version control

 Configs scattered across machines
 No backup, no history

Good: Git repository

 Store in Git repository
git init ~/dotfiles
cd ~/dotfiles
git add .bashrc .bash_profile .zshrc
git commit -m "Initial commit"
git remote add origin https://github.com/user/dotfiles
git push -u origin main

2. Modular Design

Bad: Single monolithic file

 ~/.bashrc (1000+ lines)
 All settings in one file

Good: Modular files

 ~/.bashrc
. ~/.config/shell/base.sh
. ~/.config/shell/aliases.sh
. ~/.config/shell/functions.sh
. ~/.config/shell/local.sh

3. Document Configuration

Bad: No documentation

export SOME_VAR=value  # What is this?

Good: Well-documented

 Configure HTTP proxy for corporate network
 Required for apt-get and curl to work
export HTTP_PROXY="http://proxy.company.com:8080"
export HTTPS_PROXY="http://proxy.company.com:8080"

4. Use Functions for Complex Logic

Bad: Repeated code

export PATH="$HOME/bin:$PATH"
export PATH="/usr/local/bin:$PATH"
export PATH="/opt/homebrew/bin:$PATH"

Good: Reusable function

add_to_path() {
    [ -d "$1" ] && case ":$PATH:" in
        *":$1:"*) ;;
        *) export PATH="$1:$PATH" ;;
    esac
}

add_to_path "$HOME/bin"
add_to_path "/usr/local/bin"
add_to_path "/opt/homebrew/bin"

5. Test Before Deploying

Bad: Edit production config directly

vim ~/.bashrc  # Edit directly
 Breaks shell if syntax error

Good: Test in new shell

 Edit copy
cp ~/.bashrc ~/.bashrc.new
vim ~/.bashrc.new

 Test in new shell
bash --rcfile ~/.bashrc.new

 Deploy if works
mv ~/.bashrc ~/.bashrc.backup
mv ~/.bashrc.new ~/.bashrc

Troubleshooting Common Issues

Issue 1: PATH Growing on Every Source

Symptom: PATH becomes huge after sourcing multiple times

Diagnosis:

bashrs lint ~/.bashrc | grep CONFIG-001

Solution:

 Use idempotent PATH function
add_to_path() {
    [ -d "$1" ] && case ":$PATH:" in
        *":$1:"*) ;;
        *) export PATH="$1:$PATH" ;;
    esac
}

Issue 2: Configuration Breaks on Different Shell

Symptom: Works on bash, breaks on sh/dash

Diagnosis:

shellcheck -s sh ~/.bashrc

Solution:

 Use POSIX-compliant constructs
 ❌ Bash-specific: [[ ]]
[[ -f file ]] && echo "exists"

 ✅ POSIX: [ ]
[ -f file ] && echo "exists"

Issue 3: Slow Shell Startup

Symptom: Shell takes >1 second to start

Diagnosis:

 Profile shell startup
time bash -c 'source ~/.bashrc'

 Find slow operations
bash -x ~/.bashrc 2>&1 | ts -i '%.s'

Solution:

 Lazy-load expensive operations
if command -v rbenv >/dev/null 2>&1; then
     Don't init immediately
    rbenv() {
        unset -f rbenv
        eval "$(command rbenv init -)"
        rbenv "$@"
    }
fi

Issue 4: Variables Not Properly Quoted

Symptom: Breaks when path has spaces

Diagnosis:

bashrs lint ~/.bashrc | grep CONFIG-002

Solution:

 Always quote variables
export PROJECT_DIR="${HOME}/My Projects"
[ -d "${PROJECT_DIR}" ] && cd "${PROJECT_DIR}"

Issue 5: Duplicate Alias Definitions

Symptom: Aliases behaving unexpectedly

Diagnosis:

bashrs lint ~/.bashrc | grep CONFIG-003

Solution:

 Remove duplicates, keep one definition
 ❌ Bad
alias ll="ls -l"
alias ll="ls -la"  # Overwrites

 ✅ Good
alias ll="ls -la"

Summary

Key Takeaways:

  1. Analyze configurations with bashrs config analyze
  2. Lint for issues with bashrs lint (CONFIG-001 to CONFIG-005)
  3. Purify configurations with bashrs config purify
  4. Test idempotency by sourcing multiple times
  5. Verify POSIX compliance with shellcheck
  6. Version control configurations in Git
  7. Use modular design for maintainability
  8. Test before deploying to production

Results:

  • Before: 17 issues (PATH pollution, duplicates, unquoted variables)
  • After: 0 issues, idempotent, POSIX-compliant, maintainable

Configuration Quality Checklist:

  • No PATH duplicates (CONFIG-001)
  • All variables quoted (CONFIG-002)
  • No duplicate aliases (CONFIG-003)
  • Idempotent operations (CONFIG-004)
  • Safe sourcing with checks (CONFIG-005)
  • No non-deterministic patterns (DET001)
  • No security issues (SEC rules)
  • POSIX compliant (shellcheck passes)
  • Fast startup (<100ms)
  • Version controlled
  • Modular design
  • Well documented

Next Steps:


Production Success Story:

"We had 15 engineers with 15 different .bashrc files, each with subtle bugs. After purifying with bashrs, we now have a single source-of-truth configuration in Git. Shell startup time dropped from 2.3s to 0.15s, and 'works on my machine' issues disappeared entirely."

— Infrastructure Team, High-Growth SaaS Startup