PowerShell / PowerShell/PowerShell
Add `-From` and `-To` parameters to `Select-String`
Nobody has claimed this yet.
- 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:
- Extract specific text and extract
- How to select between multiple lines in power shell?
- How to read lines between 2 special characters in txt-file with Powershell
- Unable to get data between multiple keyword using powershell
- Need Regex to match multiple lines until Match is found between common delimiters
- Extract multiple lines of text between two key words from shell command in powershell
- Extract block of text using regex and powershell
- Need to search a line from a long config file with powershell
- Powershell Regex: Reading a multi-line string between two points
- How can I deleted lines from a certain position?
- Regex match multiple lines from file
- Extract data from log file and copy data to another text file using powershell
- regex select multilines in powershell
- ...
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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