PowerShell / PowerShell/PowerShell

Add `-From` and `-To` parameters to `Select-String`

Open
#15,136 12 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue-Enhancement Needs-Triage WG-Language
Dominant language
C#
Stars
55.5k
Forks
8.5k
Avg merge
1d 2h
Merged PRs (30d)
88

Description

Add -FromPattern and -ToPattern parameters to Select-String cmdlet.

It is often required to select the lines between two other lines define by regulars expressions as show from e.g. the Stackoverflow Q&As:

To setup a function using the Select-String cmdlet and properly stream the input and output, currently requires to get track of whether any line needs to be passed thru or not. Therefore functions for this often end up in stalling the pipeline and doing an expensive regular expression over a full multiple line text string.
-FromPattern and -ToPattern parameters would allow for a better implementation and an easier syntax to perform this specific common string selection.

Include or Exclude?

This propose raises the question whether the found line that contains the -FromPattern and -ToPattern expression should be included or excluded in the output.
In my vision for this propose the output should start right after the point where the -FromPattern expression is found (and output any succeeding string) and stop right before the point where the -ToPattern expression is found (and output any preceding string). This will allow the developer to select what needs to be passed thru using the concerned regular expressions:

Prototype

function SelectString {
    [CmdletBinding()] param(
        [Parameter(ValueFromPipeLine = $True)][String]$String,
        [Regex]$FromPattern,
        [Regex]$ToPattern,
        [Switch]$MatchCase
    )
    begin {
        $PassThru = !$PSBoundParameters.ContainsKey('FromPattern') -and $PSBoundParameters.ContainsKey('ToPattern')
        if (!$MatchCase) {
            $FromPattern = '(?i)' + $FromPattern
            $ToPattern   = '(?i)' + $ToPattern
        }
    }
    process {
        $Start = 0
        do { # There could be (multiple) $FromPattern/$ToPattern matches in one line
            if ($PassThru) {
                $ToMatch = if ($PSBoundParameters.ContainsKey('ToPattern')) { $ToPattern.Match($String, $Start) }
                if ($ToMatch.Success) {
                    $PassThru = $False
                    $Length = $ToMatch.Index - $Start
                    if ($Length) { $String.SubString($Start, $Length) }
                    $Start = $ToMatch.Index + $ToMatch.Length
                }
                else {
                    $String.SubString($Start)
                    $Start = $String.Length
                }
            }
            if (!$PassThru) {
                $FromMatch = if ($PSBoundParameters.ContainsKey('FromPattern')) { $FromPattern.Match($String, $Start) }
                if ($FromMatch.Success) {
                    $PassThru = $True
                    $Start = $FromMatch.Index + $FromMatch.Length
                }
                else {
                    $Start = $String.Length
                }
            }
        } Until ($Start -ge $String.Length)
    }
}

(Note: this prototype is case sensitive.)

Examples

In the examples below the follow string list is use for $Test:

$Test = @'
[One]
[Two]
<Start>[Three]
[Four]
[Five][Six]
[Seven]<End>
[Eight]
[Nine]
'@ -Split '[\r\n]+'
Example 1

Select everything between the -From and -To expression:

$Test | SelectString -From '\<Start\>' -To '\<End\>'

[Three]
[Four]
[Five][Six]
[Seven]
Example 2

Exclude the lines that matches the -From and -To expression:
(By matching the whole line)

$Test | SelectString -From '\<Start\>.*' -To '.*\<End\>'

[Four]
[Five][Six]
Example 3

Include the lines that matches the -From and -To expression:
(By using lookbehind and lookforward regular expressions)

$Test | SelectString -From '(?=\<Start\>)' -To '(?<=\<End\>)'

<Start>[Three]
[Four]
[Five][Six]
[Seven]<End>
Example 4

Select multiple items in a single line:
(Note: # Revisit the behavior of chaining Select-String calls #14850)

$Test | SelectString -From '\<Start\>' -To '\<End\>' | SelectString -From '\[' -To '\]'

Three
Four
Five
Six
Seven

Caveats

The Select-String cmdlet has already quite some parameters, some of the parameters (like -Pattern should be mutual exclusive with these proposed -FromPattern and -ToPattern parameters.
The -Context parameter might still apply: where the first integer refers to the number of lines before the line where the -FromPattern expression is found and the second integer to the number of lines after the line where the -ToPattern expression is found.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the Select-String cmdlet entry point and review how its existing parameters, especially -Pattern and -Context, are defined and interact. Compare the proposed -FromPattern and -ToPattern behavior with the prototype and examples, then establish whether boundary matches are included or excluded before implementing and validating the feature.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, powershell
Domain
cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.