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