Skip to content

Shell Scripts

sysid edited this page Oct 12, 2025 · 2 revisions

Shell Scripts

bkmr provides powerful shell script management with interactive execution, argument passing, and direct shell integration.

Overview

Shell scripts in bkmr are bookmarks with the _shell_ system tag that execute in your terminal. They support:

  • Interactive editing before execution (default)
  • Direct execution with --no-edit flag
  • Argument passing via -- separator
  • Shell function stubs for direct command-line access
  • Vim/Emacs bindings in interactive mode
  • Command history for reuse

Execution Modes

Interactive Mode (Default)

The default behavior presents an interactive editor before execution:

# Search and execute shell script
bkmr search --fzf -t _shell_

# Or open by ID
bkmr open 123

Interactive editor features:

  • Pre-filled with script content
  • Full editing capabilities (modify, add parameters, combine commands)
  • Vim or Emacs bindings based on your shell configuration
  • Command history saved to ~/.config/bkmr/shell_history.txt
  • Press Enter to execute, Ctrl-C to cancel

Automatic binding detection:

  • Checks $ZSH_VI_MODE for zsh vi mode
  • Reads .inputrc for readline settings
  • Detects set -o vi / set -o emacs in bash
  • Defaults to emacs bindings

Direct Execution

Skip the interactive editor and execute immediately:

# Direct execution without editing
bkmr open --no-edit 123

# Useful in automation or when script is trusted
bkmr open --no-edit <id>

Passing Arguments

Pass arguments to scripts using the -- separator:

# Arguments passed as $1, $2, $3, etc.
bkmr open --no-edit 123 -- arg1 arg2 arg3

# Real-world example: deployment script
bkmr open --no-edit 456 -- --env production --dry-run

# In your script, access with:
#!/bin/bash
echo "Environment: $1"  # --env
echo "Second arg: $2"   # production
echo "Third arg: $3"    # --dry-run
echo "All args: $@"

Shell Function Stubs

⚠️ CRITICAL: The correct command is bkmr search --shell-stubs (NOT bkmr create-shell-stubs)

Shell function stubs transform your bookmarked shell scripts into callable shell functions, enabling natural command-line execution with full argument support.

Basic Usage

# View all shell function stubs that would be created
bkmr search --shell-stubs

# Example output:
# backup-database() { bkmr open --no-edit 123 -- "$@"; }
# export -f backup-database
# deploy-app() { bkmr open --no-edit 124 -- "$@"; }
# export -f deploy-app
# monitoring-setup() { bkmr open --no-edit 125 -- "$@"; }
# export -f monitoring-setup

Integration Strategies

Method 1: Dynamic Loading (Recommended for Development)

# Source directly into current shell - always fresh
source <(bkmr search --shell-stubs)

# Add to your shell profile for automatic loading
echo 'source <(bkmr search --shell-stubs)' >> ~/.bashrc
echo 'source <(bkmr search --shell-stubs)' >> ~/.zshrc

Benefits:

  • Always reflects current bookmarks
  • Automatically includes new shell script bookmarks
  • No maintenance required

Considerations:

  • Small startup delay (typically <100ms)
  • Requires bkmr to be available in PATH

Method 2: Static Caching (Recommended for Production)

# Generate static functions file
bkmr search --shell-stubs > ~/.config/bkmr/shell-functions.sh

# Source the cached file in your profile
echo 'source ~/.config/bkmr/shell-functions.sh' >> ~/.bashrc

# Update when you add new shell script bookmarks
alias update-shell-stubs='bkmr search --shell-stubs > ~/.config/bkmr/shell-functions.sh'

Benefits:

  • Faster shell startup
  • Works without bkmr in PATH
  • Explicit control over updates

Considerations:

  • Manual refresh needed when bookmarks change
  • Potential for stale functions

Advanced Usage Patterns

Selective Function Loading

# Create functions only for specific tags
source <(bkmr search --tags _shell_,development --shell-stubs)

# Combine with tag filtering
source <(bkmr search --tags _shell_,production --shell-stubs)

Function Namespace Management

# Prefix all functions to avoid conflicts
bkmr search --shell-stubs | sed 's/^/bkmr_/' > ~/.config/bkmr/namespaced-functions.sh

# Creates: bkmr_backup-database(), bkmr_deploy-app(), etc.
source ~/.config/bkmr/namespaced-functions.sh

Project-Specific Workflows

# Create project-specific shell stub files
project-stubs() {
    local project="$1"
    bkmr search --tags _shell_,"$project" --shell-stubs > ".${project}-stubs.sh"
    echo "Created .${project}-stubs.sh - source it with: source .${project}-stubs.sh"
}

# Usage
project-stubs myapp
source .myapp-stubs.sh

# Now use project-specific commands
myapp-deploy staging
myapp-backup production

Real-World Workflow Examples

DevOps Toolkit

# Add to ~/.bashrc or ~/.zshrc
source <(bkmr search --shell-stubs)

# Now your bookmarked scripts become part of your shell environment:
backup-database production --incremental
deploy-microservice user-auth staging --canary-percentage 10
scale-cluster monitoring --nodes 5
update-certificates *.example.com --dry-run

# All with full argument support and tab completion (if configured)

Chained Workflows

# Create deployment workflow using multiple script stubs
deploy-full() {
    local env="${1:-staging}"

    echo "Running full deployment to $env..."
    backup-database "$env"
    run-tests "$env"
    deploy-application "$env"
    verify-deployment "$env"
}

# All functions are generated from bookmarked shell scripts

Function Name Conventions

The bkmr search --shell-stubs command follows these naming rules:

  • Preserves hyphens: "backup-database"backup-database()
  • Converts spaces to underscores: "Deploy Script"deploy_script()
  • Handles special characters: "My Awesome Script!"my_awesome_script()
  • Prevents numeric start: "2fa-setup"script-2fa-setup()
  • Fallback for invalid names: "!@#$%"shell_script()

Examples:

# Bookmark Title              → Function Name
"Database Backup"database_backup()
"deploy-to-production"deploy-to-production()
"Run Tests (CI)"run_tests_ci()
"2fa-setup"script-2fa-setup()

Best Practices

1. Use Descriptive Bookmark Titles:

# Good: Clear, concise titles become readable functions
bkmr add "script content" ops,_shell_ --title "backup-database"
bkmr add "script content" deploy,_shell_ --title "deploy-to-production"

# Avoid: Generic or unclear titles
bkmr add "script content" ops,_shell_ --title "script1"
bkmr add "script content" deploy,_shell_ --title "do-stuff"

2. Tag Consistently:

# Use consistent tags for filtering
bkmr add "script" production,database,_shell_ --title "db-backup"
bkmr add "script" production,app,_shell_ --title "app-deploy"

# Generate only production scripts
source <(bkmr search --tags _shell_,production --shell-stubs)

3. Test Function Names:

# Preview function names before sourcing
bkmr search --shell-stubs | grep '^[a-zA-Z]' | cut -d'(' -f1

# Check for conflicts with existing commands
bkmr search --shell-stubs | grep '^[a-zA-Z]' | cut -d'(' -f1 | \
while read func; do type "$func" 2>&1 | grep -q "is a" && echo "Conflict: $func"; done

4. Document Complex Functions:

# Add comments in your shell profile
# bkmr shell function stubs - auto-generated
source <(bkmr search --shell-stubs)
# Usage: backup-database [environment] [--incremental]
# Usage: deploy-app [service-name] [environment]

5. Regular Cleanup:

# Periodically review shell script bookmarks
bkmr search --tags _shell_ --json | jq -r '.[] | "\(.id): \(.title)"'

# Remove unused scripts
bkmr delete <id>

Troubleshooting

Function Name Conflicts

# Check for conflicts before sourcing
bkmr search --shell-stubs | grep '^[a-zA-Z]' | cut -d'(' -f1 | sort | uniq -d

# Resolution strategies:
# 1. Rename conflicting bookmarks
# 2. Use namespacing (prefix with "bkmr_")
# 3. Use selective loading with tag filters

Performance Issues

# Profile shell startup time
time (source <(bkmr search --shell-stubs))

# If too slow, switch to static caching
bkmr search --shell-stubs > ~/.config/bkmr/shell-functions.sh
# Then source the cached file in your profile

Missing Functions

# Verify shell script bookmarks exist
bkmr search --tags _shell_ --json | jq length

# Check specific bookmark has _shell_ tag
bkmr show <id> | grep "_shell_"

# Verify functions are properly exported
declare -F | grep -E "(backup|deploy|monitoring)"

Configuration

Disable Interactive Mode Globally

# Via environment variable
export BKMR_SHELL_INTERACTIVE=false

# Or in ~/.config/bkmr/config.toml
[shell_opts]
interactive = false

With interactive mode disabled, bkmr open <id> executes directly without the editor.

Shell History

All executed commands (from interactive mode) are saved to:

~/.config/bkmr/shell_history.txt

This provides a record of executed scripts for auditing or reuse.

Examples

Basic Shell Script Management

# Add a deployment script
bkmr add "#!/bin/bash
echo 'Deploying application...'
ssh server 'cd /app && git pull && systemctl restart app'
" deploy,production,_shell_ --title "deploy-production"

# Execute with interactive editing
bkmr search --fzf -t _shell_,deploy

# Execute directly
bkmr open --no-edit <id>

# Execute with parameters
bkmr open --no-edit <id> -- --dry-run --verbose

Complex Workflow with Arguments

# Create a parameterized backup script
bkmr add '#!/bin/bash
ENV=$1
INCREMENTAL=$2

if [[ "$INCREMENTAL" == "--incremental" ]]; then
    echo "Running incremental backup for $ENV"
    pg_dump -h "$ENV-db" myapp | gzip > "backup-$ENV-$(date +%Y%m%d)-incr.sql.gz"
else
    echo "Running full backup for $ENV"
    pg_dump -h "$ENV-db" myapp | gzip > "backup-$ENV-$(date +%Y%m%d)-full.sql.gz"
fi
' database,backup,_shell_ --title "backup-database"

# Use via shell stub
source <(bkmr search --shell-stubs)
backup-database production --incremental
backup-database staging

Multi-Environment Scripts

# Add environment-aware script
bkmr add '#!/bin/bash
ENV=${1:-staging}

case $ENV in
    production)
        echo "Deploying to PRODUCTION"
        DEPLOY_HOST="prod.example.com"
        ;;
    staging)
        echo "Deploying to STAGING"
        DEPLOY_HOST="staging.example.com"
        ;;
    *)
        echo "Unknown environment: $ENV"
        exit 1
        ;;
esac

ssh "$DEPLOY_HOST" "cd /app && git pull && systemctl restart app"
' deploy,_shell_ --title "deploy-environment-aware"

# Execute with environment
bkmr open --no-edit <id> -- production
bkmr open --no-edit <id> -- staging

Related Pages

Clone this wiki locally