Skip to content

Commit 48c7e11

Browse files
Jawz84Andrew
authored andcommitted
Add -Raw switch to Select-String for convenience (#9901)
1 parent 8de061f commit 48c7e11

2 files changed

Lines changed: 75 additions & 17 deletions

File tree

src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,10 +289,18 @@ internal MatchInfo Clone()
289289
/// <summary>
290290
/// A cmdlet to search through strings and files for particular patterns.
291291
/// </summary>
292-
[Cmdlet(VerbsCommon.Select, "String", DefaultParameterSetName = "File", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113388")]
293-
[OutputType(typeof(MatchInfo), typeof(bool))]
292+
[Cmdlet(VerbsCommon.Select, "String", DefaultParameterSetName = ParameterSetFile, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113388")]
293+
[OutputType(typeof(bool), typeof(MatchInfo), ParameterSetName = new[] { ParameterSetFile, ParameterSetObject, ParameterSetLiteralFile })]
294+
[OutputType(typeof(string), ParameterSetName = new[] { ParameterSetFileRaw, ParameterSetObjectRaw, ParameterSetLiteralFileRaw })]
294295
public sealed class SelectStringCommand : PSCmdlet
295296
{
297+
private const string ParameterSetFile = "File";
298+
private const string ParameterSetFileRaw = "FileRaw";
299+
private const string ParameterSetObject = "Object";
300+
private const string ParameterSetObjectRaw = "ObjectRaw";
301+
private const string ParameterSetLiteralFile = "LiteralFile";
302+
private const string ParameterSetLiteralFileRaw = "LiteralFileRaw";
303+
296304
/// <summary>
297305
/// A generic circular buffer.
298306
/// </summary>
@@ -965,7 +973,8 @@ void IContextTracker.TrackEOF()
965973
/// <summary>
966974
/// Gets or sets the current pipeline object.
967975
/// </summary>
968-
[Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = "Object")]
976+
[Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = ParameterSetObject)]
977+
[Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = ParameterSetObjectRaw)]
969978
[AllowNull]
970979
[AllowEmptyString]
971980
public PSObject InputObject
@@ -988,15 +997,17 @@ public PSObject InputObject
988997
/// Gets or sets files to read from.
989998
/// Globbing is done on these.
990999
/// </summary>
991-
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "File")]
1000+
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetFile)]
1001+
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetFileRaw)]
9921002
[FileinfoToString]
9931003
public string[] Path { get; set; }
9941004

9951005
/// <summary>
9961006
/// Gets or sets literal files to read from.
9971007
/// Globbing is not done on these.
9981008
/// </summary>
999-
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "LiteralFile")]
1009+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetLiteralFile)]
1010+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetLiteralFileRaw)]
10001011
[FileinfoToString]
10011012
[Alias("PSPath", "LP")]
10021013
public string[] LiteralPath
@@ -1011,6 +1022,15 @@ public string[] LiteralPath
10111022

10121023
private bool _isLiteralPath;
10131024

1025+
/// <summary>
1026+
/// Gets or sets a value indicating if only string values containing matched lines should be returned.
1027+
/// If not (default) return MatchInfo (or bool objects, when Quiet is passed).
1028+
/// </summary>
1029+
[Parameter(Mandatory = true, ParameterSetName = ParameterSetObjectRaw)]
1030+
[Parameter(Mandatory = true, ParameterSetName = ParameterSetFileRaw)]
1031+
[Parameter(Mandatory = true, ParameterSetName = ParameterSetLiteralFileRaw)]
1032+
public SwitchParameter Raw { get; set; }
1033+
10141034
/// <summary>
10151035
/// Gets or sets a value indicating if a pattern string should be matched literally.
10161036
/// If not (default) search using pattern as a Regular Expression.
@@ -1028,7 +1048,9 @@ public string[] LiteralPath
10281048
/// Gets or sets a value indicating if the cmdlet will stop processing at the first successful match and
10291049
/// return true. If both List and Quiet parameters are given, an exception is thrown.
10301050
/// </summary>
1031-
[Parameter]
1051+
[Parameter(ParameterSetName = ParameterSetObject)]
1052+
[Parameter(ParameterSetName = ParameterSetFile)]
1053+
[Parameter(ParameterSetName = ParameterSetLiteralFile)]
10321054
public SwitchParameter Quiet { get; set; }
10331055

10341056
/// <summary>
@@ -1160,7 +1182,10 @@ public string[] Exclude
11601182

11611183
private int _postContext = 0;
11621184

1163-
private IContextTracker GetContextTracker() => (_preContext == 0 && _postContext == 0) ? _noContextTracker : new ContextTracker(_preContext, _postContext);
1185+
// When we are in Raw mode or pre- and postcontext are zero, use the _noContextTracker, since we will not be needing trackedLines.
1186+
private IContextTracker GetContextTracker() => (Raw || (_preContext == 0 && _postContext == 0))
1187+
? _noContextTracker
1188+
: new ContextTracker(_preContext, _postContext);
11641189

11651190
// This context tracker is only used for strings which are piped
11661191
// directly into the cmdlet. File processing doesn't need
@@ -1425,8 +1450,14 @@ private bool FlushTrackerQueue(IContextTracker contextTracker)
14251450
return false;
14261451
}
14271452

1428-
// If -quiet is specified but not -list return true on first match
1429-
if (Quiet && !List)
1453+
if (Raw)
1454+
{
1455+
foreach (MatchInfo match in contextTracker.EmitQueue)
1456+
{
1457+
WriteObject(match.Line);
1458+
}
1459+
}
1460+
else if (Quiet && !List)
14301461
{
14311462
WriteObject(true);
14321463
}

test/powershell/Modules/Microsoft.PowerShell.Utility/Select-String.Tests.ps1

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,24 @@ Describe "Select-String" -Tags "CI" {
6868
}
6969

7070
it "Should return an array of non matching strings when the switch of NotMatch is used and the string do not match" {
71-
$testinputone | Select-String -Pattern "goodbye" -NotMatch | Should -Be "hello", "hello"
71+
$testinputone | Select-String -Pattern "goodbye" -NotMatch | Should -BeExactly "hello", "Hello"
7272
}
7373

7474
it "Should return the same as NotMatch" {
7575
$firstMatch = $testinputone | Select-String -pattern "goodbye" -NotMatch
7676
$secondMatch = $testinputone | Select-String -pattern "goodbye" -n
7777

7878
$equal = @(Compare-Object $firstMatch $secondMatch).Length -eq 0
79-
$equal | Should -Be True
79+
$equal | Should -BeTrue
80+
}
81+
82+
It "Should return a string type when -Raw is used" {
83+
$result = $testinputtwo | Select-String -Pattern "hello" -CaseSensitive -Raw
84+
$result | Should -BeOfType "System.String"
85+
}
86+
87+
It "Should return ParameterBindingException when -Raw and -Quiet are used together" {
88+
{ $testinputone | Select-String -Pattern "hello" -Raw -Quiet -ErrorAction Stop } | Should -Throw -ExceptionType ([System.Management.Automation.ParameterBindingException])
8089
}
8190
}
8291

@@ -106,13 +115,13 @@ Describe "Select-String" -Tags "CI" {
106115
It "Should return the name of the file and the string that 'string' is found if there is only one lines that has a match" {
107116
$expected = $testInputFile + ":1:This is a text string, and another string"
108117

109-
Select-String $testInputFile -Pattern "string" | Should -Be $expected
118+
Select-String $testInputFile -Pattern "string" | Should -BeExactly $expected
110119
}
111120

112121
It "Should return all strings where 'second' is found in testfile1 if there is only one lines that has a match" {
113122
$expected = $testInputFile + ":2:This is the second line"
114123

115-
Select-String $testInputFile -Pattern "second"| Should -Be $expected
124+
Select-String $testInputFile -Pattern "second"| Should -BeExactly $expected
116125
}
117126

118127
It "Should return all strings where 'in' is found in testfile1 pattern switch is not required" {
@@ -121,10 +130,10 @@ Describe "Select-String" -Tags "CI" {
121130
$expected3 = "This is the third line"
122131
$expected4 = "This is the fourth line"
123132

124-
(Select-String in $testInputFile)[0].Line | Should -Be $expected1
125-
(Select-String in $testInputFile)[1].Line | Should -Be $expected2
126-
(Select-String in $testInputFile)[2].Line | Should -Be $expected3
127-
(Select-String in $testInputFile)[3].Line | Should -Be $expected4
133+
(Select-String in $testInputFile)[0].Line | Should -BeExactly $expected1
134+
(Select-String in $testInputFile)[1].Line | Should -BeExactly $expected2
135+
(Select-String in $testInputFile)[2].Line | Should -BeExactly $expected3
136+
(Select-String in $testInputFile)[3].Line | Should -BeExactly $expected4
128137
(Select-String in $testInputFile)[4].Line | Should -BeNullOrEmpty
129138
}
130139

@@ -175,6 +184,24 @@ Describe "Select-String" -Tags "CI" {
175184

176185
Select-String 'matc*' $testInputFile -ca | Should -Match $expected
177186
}
187+
188+
It "Should return all strings where 'in' is found in testfile1, when -Raw is used." {
189+
$expected1 = "This is a text string, and another string"
190+
$expected2 = "This is the second line"
191+
$expected3 = "This is the third line"
192+
$expected4 = "This is the fourth line"
193+
194+
(Select-String in $testInputFile -Raw)[0] | Should -BeExactly $expected1
195+
(Select-String in $testInputFile -Raw)[1] | Should -BeExactly $expected2
196+
(Select-String in $testInputFile -Raw)[2] | Should -BeExactly $expected3
197+
(Select-String in $testInputFile -Raw)[3] | Should -BeExactly $expected4
198+
(Select-String in $testInputFile -Raw)[4] | Should -BeNullOrEmpty
199+
}
200+
201+
It "Should ignore -Context parameter when -Raw is used." {
202+
$expected = "This is the second line"
203+
Select-String second $testInputFile -Raw -Context 2,2 | Should -BeExactly $expected
204+
}
178205
}
179206
Push-Location $currentDirectory
180207
}

0 commit comments

Comments
 (0)