-
-
Notifications
You must be signed in to change notification settings - Fork 0
Script Examples
Joao Palma edited this page Oct 27, 2025
·
4 revisions
← Back to README | Home | Troubleshooting →
- Basic Examples
- Git Automation
- Development Tools
- Deployment Scripts
- System Utilities
- Team Examples
- Advanced Patterns
#!/usr/bin/env bash
### DOC
# hello - Simple greeting script
#
# Usage: dr hello [name]
#
# Examples:
# dr hello
# dr hello Alice
### DOC
name="${1:-World}"
echo "Hello, $name!"#!/usr/bin/env bash
### DOC
# prompt - Interactive user input example
#
# Usage: dr prompt
### DOC
read -p "What's your name? " name
read -p "What's your favorite color? " color
echo "Hello $name! $color is a great color!"#!/usr/bin/env bash
### DOC
# args-demo - Demonstrate argument parsing
#
# Usage: dr args-demo [options] <file>
#
# Options:
# -v, --verbose Enable verbose output
# -f, --force Force operation
# -o, --output Output file
### DOC
VERBOSE=false
FORCE=false
OUTPUT=""
while [[ $# -gt 0 ]]; do
case $1 in
-v | --verbose)
VERBOSE=true
shift
;;
-f | --force)
FORCE=true
shift
;;
-o | --output)
OUTPUT="$2"
shift 2
;;
-*)
echo "Unknown option: $1"
exit 1
;;
*)
FILE="$1"
shift
;;
esac
done
[[ "$VERBOSE" == true ]] && echo "Verbose mode enabled"
[[ "$FORCE" == true ]] && echo "Force mode enabled"
[[ -n "$OUTPUT" ]] && echo "Output file: $OUTPUT"
[[ -n "$FILE" ]] && echo "Input file: $FILE"#!/usr/bin/env bash
### DOC
# git/quick-commit - Fast git commit with generated message
#
# Usage: dr git/quick-commit [message]
#
# If no message provided, generates one from changes
#
# Examples:
# dr git/quick-commit
# dr git/quick-commit "Fix typo"
### DOC
set -euo pipefail
# Check for changes
if [[ -z $(git status --porcelain) ]]; then
echo "No changes to commit"
exit 0
fi
# Generate or use provided message
if [[ $# -eq 0 ]]; then
# Auto-generate message from changes
added=$(git diff --cached --name-only --diff-filter=A | wc -l)
modified=$(git diff --cached --name-only --diff-filter=M | wc -l)
deleted=$(git diff --cached --name-only --diff-filter=D | wc -l)
message="Update: "
[[ $added -gt 0 ]] && message+="$added added, "
[[ $modified -gt 0 ]] && message+="$modified modified, "
[[ $deleted -gt 0 ]] && message+="$deleted deleted"
message=${message%, }
else
message="$*"
fi
# Stage and commit
git add -A
git commit -m "$message"
echo "✓ Committed: $message"#!/usr/bin/env bash
### DOC
# git/branch-cleanup - Remove merged branches
#
# Safely removes local branches that have been merged to main/master
#
# Usage: dr git/branch-cleanup [--dry-run]
#
# Options:
# --dry-run Show what would be deleted
### DOC
set -euo pipefail
DRY_RUN=false
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true
# Get default branch
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')
# Get merged branches
BRANCHES=$(git branch --merged "$DEFAULT_BRANCH" | grep -v "^[* ] $DEFAULT_BRANCH$" | sed 's/^[ *]*//')
if [[ -z "$BRANCHES" ]]; then
echo "No merged branches to clean up"
exit 0
fi
echo "Branches merged to $DEFAULT_BRANCH:"
echo "$BRANCHES"
if [[ "$DRY_RUN" == true ]]; then
echo ""
echo "Run without --dry-run to delete these branches"
else
echo ""
read -p "Delete these branches? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "$BRANCHES" | xargs -n 1 git branch -d
echo "✓ Deleted merged branches"
else
echo "Cancelled"
fi
fi#!/usr/bin/env bash
### DOC
# git/pr-create - Create pull request with template
#
# Creates a PR with a standard template and opens in browser
#
# Usage: dr git/pr-create [title]
#
# Requires: gh (GitHub CLI)
### DOC
set -euo pipefail
# Check for gh
if ! command -v gh &>/dev/null; then
echo "Error: GitHub CLI (gh) is required"
echo "Install: https://cli.github.com/"
exit 1
fi
# Get PR title
if [[ $# -eq 0 ]]; then
# Generate from branch name
branch=$(git branch --show-current)
title=$(echo "$branch" | sed 's/[-_]/ /g' | sed 's/\b\(.\)/\u\1/g')
else
title="$*"
fi
# Create PR body template
body=$(
cat <<'EOF'
## Summary
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tests pass locally
- [ ] Added new tests
- [ ] Updated documentation
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added where needed
EOF
)
# Create PR
gh pr create --title "$title" --body "$body" --web#!/usr/bin/env bash
### DOC
# dev/react-component - Generate React component boilerplate
#
# Usage: dr dev/react-component <ComponentName> [--typescript]
#
# Options:
# --typescript Generate TypeScript component
#
# Examples:
# dr dev/react-component Button
# dr dev/react-component Card --typescript
### DOC
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Error: Component name required"
exit 1
fi
COMPONENT_NAME="$1"
USE_TS=false
[[ "${2:-}" == "--typescript" ]] && USE_TS=true
# File extension
EXT="jsx"
[[ "$USE_TS" == true ]] && EXT="tsx"
# Create component directory
mkdir -p "$COMPONENT_NAME"
# Component file
if [[ "$USE_TS" == true ]]; then
cat >"$COMPONENT_NAME/$COMPONENT_NAME.$EXT" <<EOF
import React from 'react';
import './$COMPONENT_NAME.css';
interface ${COMPONENT_NAME}Props {
// Add props here
}
export const $COMPONENT_NAME: React.FC<${COMPONENT_NAME}Props> = (props) => {
return (
<div className="$COMPONENT_NAME">
<h1>$COMPONENT_NAME Component</h1>
</div>
);
};
EOF
else
cat >"$COMPONENT_NAME/$COMPONENT_NAME.$EXT" <<EOF
import React from 'react';
import './$COMPONENT_NAME.css';
export const $COMPONENT_NAME = (props) => {
return (
<div className="$COMPONENT_NAME">
<h1>$COMPONENT_NAME Component</h1>
</div>
);
};
EOF
fi
# CSS file
cat >"$COMPONENT_NAME/$COMPONENT_NAME.css" <<EOF
.$COMPONENT_NAME {
/* Add styles here */
}
EOF
# Index file
cat >"$COMPONENT_NAME/index.$EXT" <<EOF
export { $COMPONENT_NAME } from './$COMPONENT_NAME';
EOF
# Test file
cat >"$COMPONENT_NAME/$COMPONENT_NAME.test.$EXT" <<EOF
import { render, screen } from '@testing-library/react';
import { $COMPONENT_NAME } from './$COMPONENT_NAME';
describe('$COMPONENT_NAME', () => {
it('renders without crashing', () => {
render(<$COMPONENT_NAME />);
expect(screen.getByText('$COMPONENT_NAME Component')).toBeInTheDocument();
});
});
EOF
echo "✓ Created $COMPONENT_NAME component in ./$COMPONENT_NAME/"#!/usr/bin/env bash
### DOC
# dev/api-test - Run API endpoint tests
#
# Usage: dr dev/api-test <endpoint> [--method GET|POST|PUT|DELETE]
#
# Options:
# --method HTTP method (default: GET)
# --data JSON data for POST/PUT
# --token Auth token
#
# Examples:
# dr dev/api-test /users
# dr dev/api-test /users --method POST --data '{"name":"John"}'
### DOC
set -euo pipefail
API_BASE="${API_BASE:-http://localhost:3000/api}"
METHOD="GET"
DATA=""
TOKEN="${API_TOKEN:-}"
# Parse arguments
ENDPOINT="$1"
shift
while [[ $# -gt 0 ]]; do
case $1 in
--method)
METHOD="$2"
shift 2
;;
--data)
DATA="$2"
shift 2
;;
--token)
TOKEN="$2"
shift 2
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Build curl command
CURL_CMD="curl -X $METHOD"
CURL_CMD+=" -H 'Content-Type: application/json'"
[[ -n "$TOKEN" ]] && CURL_CMD+=" -H 'Authorization: Bearer $TOKEN'"
[[ -n "$DATA" ]] && CURL_CMD+=" -d '$DATA'"
CURL_CMD+=" ${API_BASE}${ENDPOINT}"
# Execute and format
echo "Testing: $METHOD $ENDPOINT"
echo "Command: $CURL_CMD"
echo "---"
eval "$CURL_CMD" | jq '.' || eval "$CURL_CMD"#!/usr/bin/env bash
### DOC
# deploy/docker - Deploy application with Docker
#
# Usage: dr deploy/docker <environment> [--build]
#
# Arguments:
# environment Target environment (dev|staging|prod)
#
# Options:
# --build Rebuild images before deploying
#
# Examples:
# dr deploy/docker staging
# dr deploy/docker prod --build
### DOC
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Error: Environment required (dev|staging|prod)"
exit 1
fi
ENV="$1"
BUILD=false
[[ "${2:-}" == "--build" ]] && BUILD=true
# Validate environment
case "$ENV" in
dev | staging | prod) ;;
*)
echo "Error: Invalid environment: $ENV"
exit 1
;;
esac
# Load environment config
ENV_FILE=".env.$ENV"
if [[ ! -f "$ENV_FILE" ]]; then
echo "Error: Environment file not found: $ENV_FILE"
exit 1
fi
echo "Deploying to $ENV environment..."
# Build if requested
if [[ "$BUILD" == true ]]; then
echo "Building images..."
docker-compose -f docker-compose.yml -f docker-compose.$ENV.yml build
fi
# Deploy
echo "Starting containers..."
docker-compose -f docker-compose.yml -f docker-compose.$ENV.yml up -d
# Health check
echo "Waiting for health check..."
sleep 5
if docker-compose ps | grep -q "healthy"; then
echo "✓ Deployment successful!"
docker-compose ps
else
echo "✗ Health check failed!"
docker-compose logs --tail=50
exit 1
fi#!/usr/bin/env bash
### DOC
# deploy/k8s - Deploy to Kubernetes cluster
#
# Usage: dr deploy/k8s <app> <version> [--namespace prod]
#
# Arguments:
# app Application name
# version Version tag
#
# Options:
# --namespace Kubernetes namespace (default: default)
# --dry-run Show what would be deployed
#
# Examples:
# dr deploy/k8s myapp v1.2.3
# dr deploy/k8s myapp v1.2.3 --namespace production
### DOC
set -euo pipefail
if [[ $# -lt 2 ]]; then
echo "Error: App name and version required"
exit 1
fi
APP="$1"
VERSION="$2"
NAMESPACE="default"
DRY_RUN=""
shift 2
# Parse options
while [[ $# -gt 0 ]]; do
case $1 in
--namespace)
NAMESPACE="$2"
shift 2
;;
--dry-run)
DRY_RUN="--dry-run=client"
shift
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
echo "Deploying $APP:$VERSION to $NAMESPACE namespace"
# Update image
kubectl set image deployment/$APP $APP=$APP:$VERSION \
--namespace=$NAMESPACE \
$DRY_RUN
if [[ -z "$DRY_RUN" ]]; then
# Wait for rollout
echo "Waiting for rollout..."
kubectl rollout status deployment/$APP \
--namespace=$NAMESPACE \
--timeout=300s
echo "✓ Deployment complete!"
# Show status
kubectl get pods -l app=$APP --namespace=$NAMESPACE
fi#!/usr/bin/env bash
### DOC
# utils/backup - Backup important directories
#
# Usage: dr utils/backup [--compress]
#
# Options:
# --compress Compress backup with gzip
# --exclude Exclude pattern (can be used multiple times)
#
# Environment:
# BACKUP_DIRS Directories to backup (default: Documents, Pictures)
# BACKUP_DEST Backup destination (default: ~/Backups)
### DOC
set -euo pipefail
COMPRESS=false
EXCLUDES=()
BACKUP_DIRS="${BACKUP_DIRS:-Documents Pictures}"
BACKUP_DEST="${BACKUP_DEST:-$HOME/Backups}"
# Parse options
while [[ $# -gt 0 ]]; do
case $1 in
--compress)
COMPRESS=true
shift
;;
--exclude)
EXCLUDES+=("--exclude=$2")
shift 2
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Create backup directory
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DEST/backup_$TIMESTAMP"
mkdir -p "$BACKUP_PATH"
echo "Starting backup to $BACKUP_PATH"
# Backup each directory
for dir in $BACKUP_DIRS; do
if [[ -d "$HOME/$dir" ]]; then
echo "Backing up $dir..."
rsync -av "${EXCLUDES[@]}" "$HOME/$dir/" "$BACKUP_PATH/$dir/"
else
echo "Warning: $dir not found, skipping"
fi
done
# Compress if requested
if [[ "$COMPRESS" == true ]]; then
echo "Compressing backup..."
tar -czf "$BACKUP_PATH.tar.gz" -C "$BACKUP_DEST" "backup_$TIMESTAMP"
rm -rf "$BACKUP_PATH"
echo "✓ Backup completed: $BACKUP_PATH.tar.gz"
else
echo "✓ Backup completed: $BACKUP_PATH"
fi
# Show backup size
du -sh "$BACKUP_DEST/backup_$TIMESTAMP"*#!/usr/bin/env bash
### DOC
# utils/sysinfo - Display system information
#
# Usage: dr utils/sysinfo [--json]
#
# Options:
# --json Output in JSON format
### DOC
set -euo pipefail
JSON_OUTPUT=false
[[ "${1:-}" == "--json" ]] && JSON_OUTPUT=true
# Gather info
HOSTNAME=$(hostname)
OS=$(uname -s)
KERNEL=$(uname -r)
ARCH=$(uname -m)
UPTIME=$(uptime -p 2>/dev/null || uptime)
CPU=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | xargs)
MEMORY=$(free -h 2>/dev/null | awk '/^Mem:/ {print $2}')
DISK=$(df -h / | awk 'NR==2 {print $4 " free of " $2}')
if [[ "$JSON_OUTPUT" == true ]]; then
cat <<EOF
{
"hostname": "$HOSTNAME",
"os": "$OS",
"kernel": "$KERNEL",
"architecture": "$ARCH",
"uptime": "$UPTIME",
"cpu": "$CPU",
"memory": "$MEMORY",
"disk": "$DISK"
}
EOF
else
cat <<EOF
System Information
==================
Hostname: $HOSTNAME
OS: $OS
Kernel: $KERNEL
Architecture: $ARCH
Uptime: $UPTIME
CPU: $CPU
Memory: $MEMORY
Disk (root): $DISK
EOF
fi#!/usr/bin/env bash
# ~/.config/dotrun/bin/lib/common.sh
### DOC
# lib/common - Shared functions for team scripts
#
# Source this file in other scripts:
# source "$(dirname "$0")/../lib/common.sh"
### DOC
# Color output functions
red() { echo -e "\033[31m$*\033[0m"; }
green() { echo -e "\033[32m$*\033[0m"; }
yellow() { echo -e "\033[33m$*\033[0m"; }
blue() { echo -e "\033[34m$*\033[0m"; }
# Logging functions
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }
error() { red "ERROR: $*" >&2; }
success() { green "SUCCESS: $*"; }
warning() { yellow "WARNING: $*"; }
info() { blue "INFO: $*"; }
# Confirmation prompt
confirm() {
local prompt="${1:-Continue?}"
local default="${2:-n}"
if [[ "$default" == "y" ]]; then
prompt="$prompt [Y/n] "
else
prompt="$prompt [y/N] "
fi
read -r -p "$prompt" response
response=${response:-$default}
[[ "$response" =~ ^[Yy]$ ]]
}
# Check dependencies
require_command() {
local cmd="$1"
if ! command -v "$cmd" &>/dev/null; then
error "$cmd is required but not installed"
return 1
fi
}
# Retry function
retry() {
local retries="${1:-3}"
local delay="${2:-1}"
shift 2
local count=0
until "$@"; do
count=$((count + 1))
if [[ $count -lt $retries ]]; then
warning "Attempt $count failed, retrying in ${delay}s..."
sleep "$delay"
else
error "Failed after $retries attempts"
return 1
fi
done
}#!/usr/bin/env bash
### DOC
# team/onboard - Set up new team member environment
#
# Usage: dr team/onboard <email>
#
# Sets up:
# - Git configuration
# - SSH keys
# - Tool installation
# - Project cloning
### DOC
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Error: Email address required"
exit 1
fi
EMAIL="$1"
NAME=$(echo "$EMAIL" | cut -d@ -f1 | sed 's/[._]/ /g' | sed 's/\b\(.\)/\u\1/g')
echo "Welcome to the team, $NAME!"
echo "This script will set up your development environment."
echo ""
# Git configuration
echo "1. Configuring Git..."
git config --global user.email "$EMAIL"
git config --global user.name "$NAME"
git config --global init.defaultBranch main
git config --global pull.rebase true
# SSH key
echo "2. Setting up SSH key..."
if [[ ! -f ~/.ssh/id_ed25519 ]]; then
ssh-keygen -t ed25519 -C "$EMAIL" -f ~/.ssh/id_ed25519 -N ""
echo "✓ SSH key created"
echo ""
echo "Add this key to your GitHub account:"
cat ~/.ssh/id_ed25519.pub
echo ""
read -p "Press Enter when you've added the key..."
else
echo "✓ SSH key already exists"
fi
# Install tools
echo "3. Installing required tools..."
TOOLS="jq yq shellcheck"
for tool in $TOOLS; do
if ! command -v "$tool" &>/dev/null; then
echo "Installing $tool..."
# Add platform-specific installation
else
echo "✓ $tool already installed"
fi
done
# Clone projects
echo "4. Cloning team projects..."
PROJECTS_DIR="$HOME/projects"
mkdir -p "$PROJECTS_DIR"
REPOS=(
"git@github.com:team/main-app.git"
"git@github.com:team/api.git"
"git@github.com:team/docs.git"
)
for repo in "${REPOS[@]}"; do
repo_name=$(basename "$repo" .git)
if [[ ! -d "$PROJECTS_DIR/$repo_name" ]]; then
echo "Cloning $repo_name..."
git clone "$repo" "$PROJECTS_DIR/$repo_name"
else
echo "✓ $repo_name already cloned"
fi
done
# Import team scripts
echo "5. Importing team DotRun scripts..."
if [[ -f ~/Downloads/team-scripts.tar.gz ]]; then
dr collection import ~/Downloads/team-scripts.tar.gz
else
echo "Download team-scripts.tar.gz and run:"
echo " dr collection import ~/Downloads/team-scripts.tar.gz"
fi
echo ""
echo "✓ Onboarding complete!"
echo ""
echo "Next steps:"
echo "1. Review team documentation in $PROJECTS_DIR/docs"
echo "2. Run 'dr team/setup-dev' to configure development environment"
echo "3. Join #dev-team Slack channel"#!/usr/bin/env bash
### DOC
# advanced/parallel-process - Process files in parallel
#
# Usage: dr advanced/parallel-process <directory>
#
# Processes all .log files in parallel using GNU parallel
### DOC
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Error: Directory required"
exit 1
fi
DIR="$1"
if ! command -v parallel &>/dev/null; then
echo "Error: GNU parallel required"
echo "Install: apt/brew install parallel"
exit 1
fi
process_file() {
local file="$1"
echo "Processing: $file"
# Simulate processing
grep -c ERROR "$file" || echo "0 errors"
# Real processing would go here
# compress, analyze, upload, etc.
}
export -f process_file
# Find and process files in parallel
find "$DIR" -name "*.log" -type f \
| parallel -j 4 --progress process_file
echo "✓ Processing complete"#!/usr/bin/env bash
### DOC
# advanced/state-machine - Example state machine implementation
#
# Usage: dr advanced/state-machine
#
# Demonstrates a simple state machine pattern
### DOC
set -euo pipefail
# States
STATE_INIT="init"
STATE_RUNNING="running"
STATE_PAUSED="paused"
STATE_STOPPED="stopped"
# Current state
CURRENT_STATE="$STATE_INIT"
# State transitions
transition() {
local from="$1"
local to="$2"
echo "Transitioning from $from to $to"
CURRENT_STATE="$to"
# Execute state entry actions
case "$to" in
"$STATE_RUNNING")
echo "Starting process..."
;;
"$STATE_PAUSED")
echo "Pausing process..."
;;
"$STATE_STOPPED")
echo "Stopping process..."
;;
esac
}
# State machine loop
while true; do
echo "Current state: $CURRENT_STATE"
echo "Commands: start, pause, resume, stop, quit"
read -p "> " command
case "$CURRENT_STATE" in
"$STATE_INIT")
case "$command" in
start)
transition "$STATE_INIT" "$STATE_RUNNING"
;;
quit)
break
;;
*)
echo "Invalid command in INIT state"
;;
esac
;;
"$STATE_RUNNING")
case "$command" in
pause)
transition "$STATE_RUNNING" "$STATE_PAUSED"
;;
stop)
transition "$STATE_RUNNING" "$STATE_STOPPED"
;;
*)
echo "Invalid command in RUNNING state"
;;
esac
;;
"$STATE_PAUSED")
case "$command" in
resume)
transition "$STATE_PAUSED" "$STATE_RUNNING"
;;
stop)
transition "$STATE_PAUSED" "$STATE_STOPPED"
;;
*)
echo "Invalid command in PAUSED state"
;;
esac
;;
"$STATE_STOPPED")
case "$command" in
start)
transition "$STATE_STOPPED" "$STATE_RUNNING"
;;
quit)
break
;;
*)
echo "Invalid command in STOPPED state"
;;
esac
;;
esac
done
echo "State machine terminated"Want more examples? Check out:
- Git Examples - Advanced Git automation
- Development Examples - Development productivity scripts
- Team Examples - Collaboration examples