How to Implement Bash-style Ctrl+R Command History Search in PowerShell


2 views

While PowerShell doesn't have an exact Ctrl+R equivalent out of the box, it offers several built-in history navigation methods:

# Basic history navigation
Get-History    # Shows full command history
Up/Down arrows # Navigate through history
F8             # Reverse search (closest to Ctrl+R)

For a more bash-like experience, we can create a custom solution using PSReadLine (included in PowerShell 5.1+):

# First, ensure PSReadLine is available
if (Get-Module -ListAvailable -Name PSReadLine) {
    Import-Module PSReadLine
    Set-PSReadLineKeyHandler -Chord Ctrl+R -Function ReverseSearchHistory
} else {
    Write-Warning "PSReadLine module not available - limited history search"
}

For more control, here's a script that mimics bash's Ctrl+R behavior:

function Search-History {
    param(
        [Parameter(Mandatory=$true)]
        [string]$SearchTerm
    )
    
    $history = Get-History | Where-Object { $_.CommandLine -like "*$SearchTerm*" }
    if ($history) {
        $selected = $history | Out-GridView -Title "Select command" -OutputMode Single
        if ($selected) {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($selected.CommandLine)
        }
    } else {
        Write-Host "No matching commands found" -ForegroundColor Yellow
    }
}

# Bind to Ctrl+R
Set-PSReadLineKeyHandler -Chord Ctrl+R -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    $search = Read-Host "Search history"
    if ($search) {
        Search-History -SearchTerm $search
    }
}

For PowerShell Core (7+) users, the experience is even better:

# Enable predictive IntelliSense (PowerShell 7.2+)
Set-PSReadLineOption -PredictionSource History

# Enhanced key bindings
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
  • Use F7 for graphical history selection
  • Combine with Alt+F7 to clear history
  • Increase history buffer: $MaximumHistoryCount = 4096
  • Persist history between sessions using the PSReadLine module

For Linux/macOS users transitioning to PowerShell, one of the most missed features is bash's Ctrl+R reverse search through command history. While PowerShell maintains command history, it lacks this interactive search capability out of the box.

PowerShell does offer some basic history navigation:

# Up/Down arrows cycle through history
# F7 shows graphical history menu
# Get-History cmdlet shows full history
Get-History | Where-Object { $_.CommandLine -like "*git*" }

We can create a custom function that mimics bash's behavior using PSReadLine (included in PowerShell 5.1+):

# Requires PSReadLine module (included in PowerShell 5.1+)
if (Get-Module -ListAvailable -Name PSReadLine) {
    Import-Module PSReadLine
    
    # Set custom handler for Ctrl+R
    Set-PSReadLineKeyHandler -Key Ctrl+R 
                            -BriefDescription ReverseHistorySearch 
                            -LongDescription "Search history backwards" 
                            -ScriptBlock {
        [Microsoft.PowerShell.PSConsoleReadLine]::ReverseSearchHistory()
    }
    
    # Optional: Enhanced search with better matching
    Set-PSReadLineOption -HistorySearchCursorMovesToEnd
    Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
}

For environments without PSReadLine, here's a workaround using a custom function:

function Search-History {
    param(
        [string]$SearchTerm
    )
    
    $history = Get-History | ForEach-Object { $_.CommandLine }
    $results = $history | Where-Object { $_ -like "*$SearchTerm*" }
    
    if ($results.Count -eq 1) {
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert($results[0])
    }
    elseif ($results.Count -gt 1) {
        $selected = $results | Out-GridView -Title "Select command" -PassThru
        if ($selected) {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($selected)
        }
    }
}

# Bind to Ctrl+Alt+R
Set-PSReadLineKeyHandler -Chord "Ctrl+Alt+R" -ScriptBlock {
    $line = $null
    $cursor = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
    Search-History -SearchTerm $line
}

PowerShell 7 introduced enhanced history features:

# Predictive IntelliSense for history
Set-PSReadLineOption -PredictionSource History

# Show matching history as you type
Set-PSReadLineOption -PredictionViewStyle ListView

To make these changes permanent, add them to your PowerShell profile:

# Open profile file
if (!(Test-Path $PROFILE)) { New-Item -Path $PROFILE -Type File -Force }
notepad $PROFILE

# Add configuration to profile
Add-Content -Path $PROFILE -Value @'
# Enhanced history search
Import-Module PSReadLine
Set-PSReadLineKeyHandler -Key Ctrl+R -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::ReverseSearchHistory()
}
'@

For PowerShell Core on Linux/macOS, additional terminal configuration might be needed:

# Ensure terminal emulator passes Ctrl+R correctly
if ($IsLinux -or $IsMacOS) {
    Set-PSReadLineOption -BellStyle None
    Set-PSReadLineOption -EditMode Emacs
}