-
Notifications
You must be signed in to change notification settings - Fork 0
Home
The Complete User Guide for Search & Replace Tool
Welcome to the official documentation for sr (Search & Replace) – the enterprise-grade text replacement utility designed for safety, reliability, and professional workflow integration.
sr is a sophisticated command-line tool that provides safe, predictable, and auditable text replacements across multiple files. Unlike basic tools like sed -i, sr implements a comprehensive safety-first approach with industrial-strength features:
- Multi-layer binary detection to prevent accidental corruption
- Session-based backup management with complete audit trails
- One-command rollback capabilities
- Ownership and permission preservation
- Configurable safety limits and exclusions
| Feature | Benefit | Example |
|---|---|---|
| Session Tracking | Complete audit trail of every operation | sr --rollback-list |
| Multi-layer Safety | Protection against accidental data loss | Automatic backups, binary detection |
| Tool Configuration | Direct parameter passing to core utilities |
--find-opts, --sed-opts, --grep-opts
|
| Extended Search | Advanced pattern matching capabilities |
-i, -E, -w flags |
| Cross-Platform | Works on Linux, macOS, BSD systems | Consistent behavior across environments |
- New to sr? Start with Installation Guide and Quick Start Tutorial
- Looking for specific commands? Check the Command Reference
- Having issues? Visit Troubleshooting or FAQ
- Enterprise deployment? See Enterprise Deployment
sr is built on three core principles:
- Safety First: No operation should risk data loss
- Predictability: Behavior should be consistent and unambiguous
- Auditability: Every change should be traceable and reversible
- Current Stable: v6.1.0
- Minimum Requirements: Bash 5.0+, find, sed, grep
- License: MIT
- Maintainer: Mikhail Deynekin
- 📖 Documentation: This wiki is your primary resource
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📧 Email: mid1977@gmail.com
# Install and test
curl -L https://raw.githubusercontent.com/paulmann/sr-search-replace/main/sr.sh -o sr
chmod +x sr
./sr --version
# Basic usage
./sr "*.html" "old-domain.com" "new-domain.com"
# Safe testing
./sr --dry-run -v "*.js" "var " "const "Complete installation instructions for all supported platforms and environments.
sr requires a POSIX-compliant shell environment with standard utilities:
| Tool | Minimum Version | Purpose | How to Check |
|---|---|---|---|
| bash | 5.0 | Shell interpreter | bash --version |
| find | 4.0 | File discovery | find --version |
| sed | 4.0 | Stream editor | sed --version |
| grep | 3.0 | Pattern matching | grep --version |
| Tool | Purpose | Benefit |
|---|---|---|
| file | MIME type detection | Enhanced binary file detection |
| stat | File metadata | Ownership/permission preservation |
| realpath | Path resolution | Better path handling |
| bc | Mathematical calculations | Performance metrics |
# Download the latest version
curl -L https://raw.githubusercontent.com/paulmann/sr-search-replace/main/sr.sh -o sr
# Make it executable
chmod +x sr
# Test the installation
./sr --version
# Install globally (optional)
sudo cp sr /usr/local/bin/# Clone the repository
git clone https://github.com/paulmann/sr-search-replace.git
cd sr-search-replace
# Make the script executable
chmod +x sr.sh
# Create a symbolic link
sudo ln -s "$(pwd)/sr.sh" /usr/local/bin/sr
# Verify installation
sr --help | head -5Debian/Ubuntu:
# Create a DEB package structure
mkdir -p sr-package/usr/local/bin
cp sr.sh sr-package/usr/local/bin/sr
chmod 755 sr-package/usr/local/bin/sr
# Build the package
dpkg-deb --build sr-package sr_6.1.0_all.deb
# Install
sudo dpkg -i sr_6.1.0_all.debRHEL/CentOS:
# Create RPM spec file (simplified example)
cat > sr.spec << 'EOF'
Name: sr
Version: 6.1.0
Release: 1%{?dist}
Summary: Search and Replace Tool
License: MIT
%install
mkdir -p %{buildroot}/usr/local/bin
install -m 755 sr.sh %{buildroot}/usr/local/bin/sr
%files
/usr/local/bin/sr
EOF
# Build and install
rpmbuild -ba sr.spec
sudo rpm -ivh ~/rpmbuild/RPMS/x86_64/sr-6.1.0-1.el7.x86_64.rpmUbuntu/Debian:
sudo apt-get update
sudo apt-get install bash findutils sed grep file coreutilsRHEL/CentOS/Fedora:
sudo yum install bash findutils sed grep file coreutils
# or for newer versions
sudo dnf install bash findutils sed grep file coreutilsArch Linux:
sudo pacman -S bash findutils sed grep file coreutilsUsing Homebrew (Recommended):
# Install GNU versions for best compatibility
brew install bash findutils gnu-sed grep file coreutils
# Link GNU sed (important!)
brew link --force gnu-sed
# Add to PATH if needed
echo 'export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"' >> ~/.bash_profileUsing MacPorts:
sudo port install bash findutils gsed grep file coreutilsFreeBSD:
pkg install bash findutils gsed grep file coreutilsOpenBSD:
pkg_add bash findutils gsed grep file coreutilsOfficial Docker Image:
# Pull the image
docker pull ghcr.io/paulmann/sr:latest
# Run interactively
docker run -it --rm -v "$(pwd):/work" ghcr.io/paulmann/sr:latest \
sr "*.txt" "search" "replace"
# Or build your own
cat > Dockerfile << 'EOF'
FROM alpine:3.14
RUN apk add --no-cache bash findutils sed grep file coreutils
COPY sr.sh /usr/local/bin/sr
RUN chmod +x /usr/local/bin/sr
ENTRYPOINT ["/usr/local/bin/sr"]
EOFAfter installation, verify everything works correctly:
# Test 1: Check version
sr --version
# Test 2: Check dependencies
for cmd in bash find sed grep; do
if command -v $cmd >/dev/null 2>&1; then
echo "✓ $cmd: $(which $cmd)"
else
echo "✗ $cmd: NOT FOUND"
fi
done
# Test 3: Basic functionality test
cat > test-file.txt << 'EOF'
Hello World
This is a test
EOF
sr --dry-run "test-file.txt" "test" "TEST"
rm test-file.txtFrom v6.0.0 to v6.1.0:
# Backup any custom configurations
cp ~/.sr_config ~/.sr_config.backup 2>/dev/null || true
# Download new version
curl -L https://raw.githubusercontent.com/paulmann/sr-search-replace/main/sr.sh -o /tmp/sr_new
chmod +x /tmp/sr_new
# Test new version
/tmp/sr_new --version
/tmp/sr_new --dry-run "*.txt" "test" "TEST"
# Replace if tests pass
sudo cp /tmp/sr_new /usr/local/bin/sr
rm /tmp/sr_newFrom older versions:
# Full reinstallation recommended
sudo rm /usr/local/bin/sr 2>/dev/null || true
curl -L https://raw.githubusercontent.com/paulmann/sr-search-replace/main/sr.sh -o sr
chmod +x sr
sudo cp sr /usr/local/bin/# Remove the binary
sudo rm /usr/local/bin/sr 2>/dev/null || true
# Remove backup directories (if desired)
find . -type d -name "sr.backup.*" -exec rm -rf {} + 2>/dev/null || true
# Remove configuration files
rm ~/.sr_config 2>/dev/null || trueSolution: Ensure /usr/local/bin is in your PATH:
echo $PATH | grep -q "/usr/local/bin" || echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcSolution: Ensure execute permissions:
chmod +x /usr/local/bin/srSolution: Install GNU sed:
brew install gnu-sed
brew link --force gnu-sedSolution: Install the file package:
# Ubuntu/Debian
sudo apt-get install file
# RHEL/CentOS
sudo yum install file
# macOS
brew install fileAfter successful installation, proceed to:
- Quick Start Tutorial for your first operations
- Basic Examples for common use cases
- Command Reference for complete option listing
Get started with sr in 10 minutes. This tutorial covers essential operations and safety practices.
Ensure sr is installed and accessible:
sr --version
# Should output: sr - Search and Replace Tool, Version 6.1.0Let's start with a simple text replacement:
# Create a test file
echo "Hello Old World" > test.txt
echo "Another old example" >> test.txt
# Perform replacement (case-sensitive by default)
sr "test.txt" "old" "new"
# Check the result
cat test.txt
# Output:
# Hello Old World (Note: 'Old' not replaced - case sensitive)
# Another new exampleKey Takeaway: By default, sr is case-sensitive. The word "Old" wasn't replaced because it starts with capital O.
Always test before making changes:
# Create test files
echo "config_value = production" > config1.txt
echo "config_value = production" > config2.txt
# Test what would change
sr --dry-run "*.txt" "production" "staging"
# Output shows what would be changed without actually modifying files
# Now apply the changes
sr "*.txt" "production" "staging"
# Verify
grep "staging" *.txtSafety Rule #1: Always use --dry-run first when working with important files.
sr excels at batch operations:
# Create multiple HTML files
cat > page1.html << 'EOF'
<html>
<title>Old Site</title>
<body>Welcome to old.example.com</body>
</html>
EOF
cat > page2.html << 'EOF'
<html>
<title>Contact Old Site</title>
<body>Email: info@old.example.com</body>
</html>
EOF
# Replace domain in all HTML files
sr "*.html" "old.example.com" "new.example.com"
# Check results
grep -n "example.com" *.htmlThe -i flag makes searches case-insensitive:
echo "TEST value" > demo.txt
echo "test VALUE" >> demo.txt
echo "Test Value" >> demo.txt
# Case-sensitive (default) - only matches exact case
sr --dry-run "demo.txt" "test" "demo"
# Would only match line 2
# Case-insensitive - matches all variations
sr -i --dry-run "demo.txt" "test" "demo"
# Would match all three linesPrevent partial matches with word boundaries (-w flag):
echo "cat category catalog" > words.txt
# Without word boundary - replaces 'cat' everywhere
sr --dry-run "words.txt" "cat" "dog"
# Result: "dog dogegory dogalog"
# With word boundary - only replaces whole word 'cat'
sr -w --dry-run "words.txt" "cat" "dog"
# Result: "dog category catalog"sr's session system makes recovery easy:
# Make some changes
echo "Original content" > important.txt
sr "important.txt" "Original" "Modified"
# Oops! We need to undo that
sr --rollback
# Verify restoration
cat important.txt
# Output: Original contentSafety Rule #2: sr creates automatic backups. Use --rollback to recover from mistakes.
Process files recursively in directories:
# Create directory structure
mkdir -p project/{src,config,docs}
echo "api_key = old_key" > project/config/prod.cfg
echo "api_key = old_key" > project/config/dev.cfg
echo "// TODO: old implementation" > project/src/main.js
# Update all configuration files
sr "project/**/*.cfg" "old_key" "new_key"
# Update source files (non-recursive in each directory)
sr -nr "project/src/*.js" "TODO:" "DONE:"Prevent processing of certain files:
# Create test structure
mkdir -p test/{public,private}
echo "public data" > test/public/file.txt
echo "private data" > test/private/file.txt
echo "ignore this" > test/ignore.txt
# Exclude private directory and specific files
sr -xd "private" -xp "ignore.txt" "test/**/*.txt" "data" "information"Protect against accidental large-scale operations:
# Limit search depth to prevent deep recursion
sr -md 2 "**/*.log" "error" "warning"
# Limit file size (skip files larger than 10MB)
sr -xs 10 "*.log" "ERROR" "WARNING"
# Combine multiple safety limits
sr -md 3 -xs 5 -xd "node_modules,vendor" "**/*.js" "var " "const "Real-world example: Refactor a codebase:
# 1. First, always test with dry-run
sr --dry-run -v -i "src/**/*.js" "oldFunctionName" "newFunctionName"
# 2. Check for any binary files that might be affected
sr --dry-run --binary-method=multi_layer "src/**/*" "oldFunctionName" "newFunctionName"
# 3. Apply changes with comprehensive backups
sr -v -i "src/**/*.js" "oldFunctionName" "newFunctionName"
# 4. Verify the changes
grep -r "newFunctionName" src/ | head -5
# 5. Check session for possible rollback
sr --rollback-list- Exercise 1: Create three text files with the word "test" in different cases. Replace all variations with "experiment" using a single command.
-
Exercise 2: Create a directory with subdirectories. Replace "foo" with "bar" in all
.txtfiles but exclude files containing "skip" in their name. - Exercise 3: Make a change, then use rollback to revert it. Verify the original content is restored.
- Exercise 4: Use dry-run to see what would happen if you replaced "localhost" with "production-server" in all configuration files.
# Essential commands for beginners
sr --dry-run PATTERN SEARCH REPLACE # Test first
sr -v PATTERN SEARCH REPLACE # Verbose mode
sr -i PATTERN SEARCH REPLACE # Case-insensitive
sr --rollback # Undo last change
sr --rollback-list # View backup history
sr -nr PATTERN SEARCH REPLACE # Non-recursive
sr -md 3 PATTERN SEARCH REPLACE # Limit depth to 3Congratulations! You've completed the quick start tutorial. Continue with:
- Basic Examples for more practical scenarios
- Command Reference for complete option details
- Session System to understand backup and recovery
Practical examples demonstrating common use cases for sr. Each example includes the command, expected outcome, and important notes.
# Scenario: Migrate from var to const/let in JavaScript
sr -i "src/**/*.js" "var " "let "
# Note: The space after 'var' prevents matching 'variable', 'variance', etc.
# More precise: Only match at beginning of lines or after specific patterns
sr -E "src/**/*.js" "(^|[^a-zA-Z0-9_])var ([a-zA-Z0-9_]+)" "\1let \2"# Update database configuration
sr "config/**/*.{yml,yaml,json}" "localhost:5432" "db-cluster.prod.example.com:5432"
# Update multiple values in one pass (using sed opts)
sr --sed-opts="-e 's/localhost:3000/api.example.com/g' -e 's/debug: true/debug: false/g'" "config/*.yml"# Update HTTP to HTTPS
sr "website/**/*.{html,htm,css,js}" "http://example.com" "https://example.com"
# Update multiple domains
for domain in blog api static; do
sr "website/**/*" "http://$domain.old-example.com" "https://$domain.new-example.com"
done# Update copyright years
current_year=$(date +%Y)
sr -E "**/*.{js,py,html,css}" "Copyright (20[0-9]{2})-202[0-3]" "Copyright \1-$current_year"
sr -E "**/*.{js,py,html,css}" "Copyright 202[0-3]" "Copyright $current_year"# Rename a function across the codebase
sr -w "src/**/*.{js,ts,py}" "calculateTotal" "computeTotal"
# Rename a class (case-sensitive, whole words only)
sr -w "src/**/*.{js,ts}" "OldClassName" "NewClassName"
# Update imports
sr "src/**/*.{js,ts}" "from 'old-package'" "from 'new-package'"
sr "src/**/*.{js,ts}" "require('old-module')" "require('new-module')"# Mark TODOs as completed
sr -E "src/**/*.{js,py,java}" "// TODO: (.*)" "// DONE: \1"
# Add username to TODOs
username=$(whoami)
sr -E "src/**/*.{js,py,java}" "// TODO:" "// TODO($username):"
# Remove debug comments
sr "src/**/*.{js,py}" "console.debug(" "// console.debug("
sr "src/**/*.{js,py}" "print(\"DEBUG:" "# print(\"DEBUG:"# Change verbose logging to warning in production
sr -i "src/**/*.{js,py,java}" "log.debug" "log.warn"
sr -i "src/**/*.{js,py,java}" "logger.verbose" "logger.warning"
# Standardize error messages
sr "src/**/*.{js,py}" "console.error('Error:" "logger.error('Error:"# Update hostnames across configuration
sr "/etc/**/*.{conf,cfg}" "old-server-hostname" "new-server-hostname"
# Update IP addresses
sr "/etc/**/*" "192.168.1.100" "10.0.0.100"
# Update port numbers
sr -E "/etc/**/*" "port[[:space:]]*=[[:space:]]*3000" "port = 8080"# Anonymize IP addresses in logs
sr -E "logs/**/*.log" "([0-9]{1,3}\.){3}[0-9]{1,3}" "[IP_REDACTED]"
# Redact sensitive information
sr -E "logs/**/*.log" "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}" "[EMAIL_REDACTED]"
sr -E "logs/**/*.log" "[0-9]{3}-[0-9]{2}-[0-9]{4}" "[SSN_REDACTED]"# Update internal references when renaming files
# First rename the files, then update references
for file in *.old.html; do
new_name="${file%.old.html}.new.html"
mv "$file" "$new_name"
sr "**/*.{html,js,css}" "$file" "$new_name"
done# Update phone numbers
sr "website/**/*.{html,md,txt}" "+1-800-OLD-NUMBER" "+1-800-NEW-NUMBER"
# Update addresses
sr "website/**/*.{html,md}" "123 Old Street" "456 New Avenue"
# Update business hours
sr -i "website/**/*.{html,md}" "9am to 5pm" "8am to 6pm"# Update version numbers in documentation
sr "docs/**/*.{md,rst}" "version 6.0.0" "version 6.1.0"
# Update broken links
sr "docs/**/*.{md,rst}" "https://old-docs.example.com" "https://new-docs.example.com"
# Update code examples
sr "docs/**/*.{md,rst}" "python2" "python3"
sr "docs/**/*.{md,rst}" "jQuery 1.x" "jQuery 3.x"# Update multi-line configuration blocks
sr -m "config/**/*.yml" "database:\\n host:.*\\n port:.*" "database:\\n host: new-host\\n port: 5432"
# Update function signatures
sr -m "src/**/*.js" "function oldName\\(.*\\)\\n\\{" "function newName(params)\\n{"# Only replace in specific contexts using complex patterns
sr -E "src/**/*.js" "(const|let|var) oldVariable =" "\1 newVariable ="
# Update CSS with vendor prefix fallbacks
sr "css/**/*.css" "-webkit-old-property" "-webkit-new-property"
sr "css/**/*.css" "-moz-old-property" "-moz-new-property"
sr "css/**/*.css" "-ms-old-property" "-ms-new-property"
sr "css/**/*.css" "old-property" "new-property"# Replace template variables with actual values
variables=(
"COMPANY_NAME:Example Corp"
"CURRENT_YEAR:2025"
"SUPPORT_EMAIL:support@example.com"
)
for var in "${variables[@]}"; do
key="${var%%:*}"
value="${var#*:}"
sr "templates/**/*.{html,txt}" "\{\{${key}\}\}" "$value"
done# Golden rule: Always dry-run first
sr --dry-run -v "**/*.sql" "DROP TABLE" "-- DROP TABLE (commented)"
# Review what will be changed
sr --dry-run -n "**/*.py" "import sys" "import sys, os" | head -20
# Check for binary files
sr --dry-run --binary "**/*" "password" "[REDACTED]"# Create a named session for important changes
export SR_BACKUP_PREFIX="migration_$(date +%Y%m%d_%H%M%S)"
sr "**/*.conf" "old-value" "new-value"
# Test rollback before committing
sr --dry-run --rollback
# If satisfied, keep changes. If not, restore:
sr --rollback# Production safety wrapper
safe_sr() {
local pattern="$1"
local search="$2"
local replace="$3"
# Always dry-run first
sr --dry-run -v "$pattern" "$search" "$replace" || return 1
# Ask for confirmation
read -p "Apply these changes? (yes/no): " confirm
if [[ "$confirm" == "yes" ]]; then
# Apply with forced backups
sr -fb -v "$pattern" "$search" "$replace"
else
echo "Operation cancelled"
return 1
fi
}
# Usage
safe_sr "*.conf" "localhost" "production-host"Quick reference of common one-liners:
# Text file operations
sr "*.txt" "foo" "bar" # Simple replacement
sr -i "*.txt" "foo" "bar" # Case-insensitive
sr -w "*.txt" "word" "replacement" # Whole words only
sr -E "*.txt" "regex(pattern)" "repl" # Extended regex
# File management
sr "**/*.js" "search" "replace" # Recursive
sr -nr "*.js" "search" "replace" # Current directory only
sr -md 3 "**/*.js" "search" "replace" # Max depth 3
# Safety features
sr --dry-run "*.conf" "old" "new" # Test without changes
sr -fb "*.sql" "DROP" "-- DROP" # Force backup
sr --rollback # Undo last operation
sr --rollback-list # List backups
# Tool configuration
sr --find-opts="-type f -size -1M" "*.log" "ERR" "WARN"
sr --sed-opts="-e 's/foo/bar/g' -e 's/baz/qux/g'" "*.txt" "x" "y"| Pitfall | Solution | Example |
|---|---|---|
| Partial word matches | Use -w for word boundaries |
sr -w "cat" "dog" won't match "catalog" |
| Case sensitivity issues | Use -i for case-insensitive |
sr -i "test" "TEST" matches "Test", "TEST", "test" |
| Shell expansion problems | Quote patterns |
sr "*.txt" not sr *.txt
|
| Binary file warnings | Use --binary or exclude |
sr --binary "*.bin" or -xp "*.bin"
|
| Permission errors | Check file permissions | Use sudo or adjust permissions |
After mastering these basic examples, explore:
- Regular Expressions for advanced pattern matching
- Tool Configuration for customizing behavior
- Enterprise Deployment for large-scale usage
Understanding the internal architecture of sr helps you use it effectively and troubleshoot issues. This section covers the system design, components, and data flow.
sr is built on three core architectural principles:
- Modularity: Each component has a single responsibility
- Safety: Fail-safe defaults and reversible operations
- Auditability: Complete traceability of all operations
┌─────────────────────────────────────────────────────────┐
│ Command Line Interface │
│ • Argument parsing │
│ • Option validation │
│ • User interaction │
└───────────────────────────┬─────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────┐
│ Core Processing Engine │
│ • Session management │
│ • File discovery │
│ • Safety checks │
│ • Error handling │
└──────────────┬──────────────────┬───────────────────────┘
│ │
┌──────────────▼──────┐ ┌──────▼───────────────────────┐
│ File Processing │ │ Backup & Rollback │
│ • Binary detection │ │ • Session tracking │
│ • Text replacement │ │ • Backup creation │
│ • Encoding handling│ │ • Rollback execution │
└──────────────┬──────┘ └──────────────┬───────────────┘
│ │
┌──────────────▼──────────────────────────▼───────────────┐
│ External Tool Integration │
│ • find - File discovery │
│ • sed - Text replacement │
│ • grep - Pattern matching │
│ • file - Binary detection │
└─────────────────────────────────────────────────────────┘
Responsibilities:
- Parse and validate command-line arguments
- Handle user input and confirmation prompts
- Manage output formatting and logging levels
Key Functions:
# CLI Layer handles these aspects:
parse_arguments() # Parse command line
show_usage() # Display help
show_version() # Show version info
confirm_action() # User confirmation promptsResponsibilities:
- Orchestrate the entire replacement workflow
- Manage session lifecycle
- Coordinate between components
- Handle errors and rollbacks
Workflow:
graph TD
A[Start] --> B[Parse Arguments]
B --> C[Initialize Session]
C --> D[Discover Files]
D --> E{For Each File}
E --> F[Safety Checks]
F --> G[Create Backup]
G --> H[Process File]
H --> I[Track Changes]
I --> E
E --> J[All Files Processed]
J --> K[Finalize Session]
K --> L[Display Summary]
L --> M[End]
Responsibilities:
- Detect binary vs text files
- Perform text replacements
- Handle different encodings
- Preserve file metadata
Binary Detection Flow:
graph LR
A[File Input] --> B{Size > 0?}
B -->|No| C[Not Binary]
B -->|Yes| D[Grep Heuristic]
D -->|Non-text| E{File Utility Available?}
D -->|Text| C
E -->|Yes| F[MIME Type Check]
E -->|No| G[Use Grep Result]
F -->|text/*| C
F -->|Other| H[Binary]
G -->|Binary| H
G -->|Text| C
Responsibilities:
- Create and manage backup sessions
- Track modified files
- Enable one-command restoration
- Clean up old backups
Session Structure:
sr.backup.20241222_143022_123456789/
├── .sr_session_metadata # JSON-like session info
├── .sr_modified_files # List of modified files
├── .sr_file_info # Additional metadata
└── files/ # Original file backups
├── path/to/file1.txt
├── path/to/file2.conf
└── ...
-
Input Processing:
# User command sr -v "*.js" "old" "new" # Internal processing: # 1. Parse arguments # 2. Validate options # 3. Initialize session
-
File Discovery:
# Uses find command with configured options find . -name "*.js" -type f -not -path "*/sr.backup.*" # Results filtered through exclusion patterns # and safety checks
-
File Processing:
# For each file: # 1. Check if binary (skip or process based on flags) # 2. Create backup in session directory # 3. Perform replacement using sed # 4. Track modification in session
-
Session Finalization:
# After all files processed: # 1. Update session metadata # 2. Display summary # 3. Clean up old backups if configured
-
Backup Discovery:
# Find all backup directories find . -maxdepth 1 -type d -name "sr.backup.*"
-
Session Selection:
# User selects backup or uses latest # System loads session metadata
-
Restoration:
# For each file in backup: # 1. Verify backup file exists # 2. Restore with original permissions # 3. Log restoration status
sr uses a three-tier configuration system:
-
Script Defaults (lowest priority):
# Defined in script header readonly DEFAULT_MAX_DEPTH=100 readonly DEFAULT_DEBUG_MODE=false
-
Environment Variables (medium priority):
# User can override defaults export SR_MAX_DEPTH=50 export SR_DEBUG=true
-
Command Line Arguments (highest priority):
# Direct override sr -md 10 --debug "*.txt" "old" "new"
Sessions provide atomic, reversible operations:
# Session creation process:
# 1. Generate unique session ID
SESSION_ID="20241222_143022_123456789"
# 2. Create backup directory
BACKUP_DIR="sr.backup.${SESSION_ID}"
# 3. Store metadata
cat > "${BACKUP_DIR}/.sr_session_metadata" << EOF
SESSION_ID="$SESSION_ID"
SESSION_COMMAND="$0 $*"
SESSION_START_TIME="$(date)"
# ... more metadata
EOF
# 4. Track modified files
echo "modified/file.txt" >> "${BACKUP_DIR}/.sr_modified_files"sr implements a comprehensive error handling system:
# Error hierarchy:
# Level 1: User errors (invalid arguments, permissions)
# Level 2: System errors (disk full, missing tools)
# Level 3: Processing errors (individual file failures)
# Error handling flow:
process_file() {
if [[ ! -f "$file" ]]; then
log_error "File not found: $file"
return 2 # File-specific error
fi
if ! create_backup "$file"; then
log_error "Backup failed: $file"
return 4 # Backup error
fi
# ... processing continues
}
# Global error handling
trap 'handle_interrupt' INT TERM
trap 'log_error "Error at line $LINENO"' ERRsr is optimized for performance through:
- Lazy Evaluation: Only process files that match patterns
- Batch Operations: Minimize tool invocations
- Stream Processing: Handle large files without loading into memory
- Parallel Safety: Safe for concurrent execution with separate sessions
# Performance optimization examples:
# 1. Use find with -print0 for null-terminated output
# 2. Process files in batches where appropriate
# 3. Cache file metadata to avoid repeated stat calls
# 4. Use efficient grep patterns for binary detectionsr implements defense in depth:
-
Input Validation:
# Validate file paths if [[ "$path" == *".."* ]] || [[ "$path" == /proc/* ]]; then log_error "Dangerous path detected" return 1 fi
-
Permission Management:
# Preserve original permissions cp --preserve=all "$original" "$backup"
-
Session Isolation:
# Each session is independent # No cross-session file access
-
Cleanup Guarantees:
# Temporary files always cleaned up trap 'cleanup_temp_files' EXIT
sr is designed for extensibility:
-
Tool Integration:
# Custom tool paths readonly FIND_TOOL="find" readonly SED_TOOL="sed" # Can be overridden for custom implementations
-
Hook System (planned):
# Pre/post processing hooks # (Future feature)
-
Plugin Architecture (planned):
# Custom processors for different file types # (Future feature)
sr provides multiple observability levels:
-
Log Levels:
ERROR > WARNING > INFO > VERBOSE > DEBUG
-
Session Tracking:
# Complete audit trail sr --rollback-list -
Performance Metrics:
# Available in verbose/debug modes Files processed: 150 Processing time: 2.3s Rate: 65.2 files/second
sr maintains compatibility through:
-
Tool Detection:
# Detect GNU vs BSD sed if sed --version 2>/dev/null | grep -q "GNU"; then SED_INPLACE_FLAG="-i" else SED_INPLACE_FLAG="-i ''" fi
-
Fallback Mechanisms:
# If file utility not available, use grep only if ! command -v file >/dev/null; then BINARY_DETECTION_METHOD="grep_only" fi
-
Path Handling:
# Handle different path formats if command -v realpath >/dev/null; then absolute_path=$(realpath "$path") else # Fallback implementation fi
Planned architectural improvements:
- Parallel Processing: Concurrent file processing with configurable workers
- Distributed Sessions: Cross-machine session synchronization
- Plugin System: Extensible file type handlers
- REST API: HTTP interface for remote operations
- Database Backend: Alternative session storage
Simple Command Flow:
# User enters:
sr "*.txt" "hello" "world"
# What happens:
# 1. Parse: pattern="*.txt", search="hello", replace="world"
# 2. Session: Create session ID "20241222_150000_123456789"
# 3. Find: Locate all *.txt files (excluding backups)
# 4. Process: For each file, backup, replace "hello" with "world"
# 5. Finalize: Save metadata, show summaryComplex Command Flow:
sr -v -i -w -md 3 --find-opts="-type f -mtime -7" \
"*.log" "error" "warning"
# What happens:
# 1. Parse all flags and options
# 2. Build custom find command with user options
# 3. Process with verbose logging, case-insensitive, word boundaries
# 4. Limit to 3 directory levels
# 5. Only process files modified in last 7 daysTo understand what sr is doing internally:
# Enable debug mode
sr -d "*.txt" "test" "TEST"
# Debug output shows:
# - Argument parsing steps
# - File discovery results
# - Binary detection decisions
# - Backup creation details
# - sed commands executed
# - Session tracking updatesNow that you understand the architecture:
- Session System: Deep dive into backup and recovery
- Tool Configuration: Customize the underlying tools
- Performance Tuning: Optimize for your use case
This wiki is continuously updated. Contributions are welcome! See the Contributing Guide for details.