Home > Software design >  How to do multiple piping with select-string in Powershell
How to do multiple piping with select-string in Powershell

Time:05-28

I googled but did not found what I'm looking for.

I have a big file containing list of countries and people. I am aware how to do multiple piping in Linux, but the same way did not work for me in Powershell.

This is what I looked for and got nothing:

Select-String .\file -pattern 'country:[ ]{8}IR' -context 5 | Select-String -pattern 'names'

But if I separate this command into to, like below, works (in which I want to avoid creating a file to search):

Select-String .\file -pattern 'country:[ ]{8}IR' -context 5 > country
Select-String .\file -patern 'names'

*Update 1

Sample data after first grep is:

  file:1407215:names:        Hadi
  file:1407216:company:        sample
  file:1407217:city:          Tehran
  file:1407218:district:          8
  file:1407219:country:        IR
  file:1407220:admin:        Mahmoud
  file:1407221:tech:         Hamed
  file:1407222:seller:        sell@company
  file:1407223:status:         Active
  file:1407224:id:         12456

CodePudding user response:

Select-String doesn't return a [string] (or array of strings) but an object of type [MatchInfo]. The output of a MatchInfo may look like a multi line text but is split in the properties .Context.PreContext, .Line and .Context.PostContext. So you can't use this object directly to pipe it into Select-String again.

However you can cast the output to [String], -split it at the new lines and use Select-String over this array:

$MatchInfo = Select-String $file -pattern 'country:[ ]{8}IR' -context 5
[string]$MatchInfo -split [environment]::NewLine | Select-String -pattern 'names'

CodePudding user response:

From a PowerShell perspective you will be dealing with objects most of the time, it might be a good idea to get the hang of dealing with them, hence this answer can show you an alternative to parsing your file into an array of objects which can be easily manipulated, filtered, sorted and exported into structured data (such as Csv).

Supposing the test.txt looks similar to this:

names:        Hadi
company:        sample
city:          Tehran
district:          8
country:        IR
admin:        Mahmoud
tech:         Hamed
seller:        sell@company
status:         Active
id:         12456

names:        John
company:        sample
city:          Tehran
district:          8
country:        IR
admin:        Doe
tech:         Hamed
seller:        sell@company
status:         Disabled
id:         12456

For this particular case we can use a switch with the -File parameter to read the file and the -Regex switch for the conditional clauses to start capturing and outputting the capture data as objects:

$parsed = switch -Regex -File .\test.txt {
    # line starts with "names", signal to start capturing
    '^names' {
        $startcapture = $true
        $out = [ordered]@{}
    }
    # boolean is set to `$true`, capture this line and add it to the ordered dictionary
    { $startcapture } {
        $key, $value = $_.Split(':').Trim()
        $out[$key] = $value
    }
    # line starts with "id", signal to output the object, and restart the capture boolean
    '^id' {
        $startcapture = $false
        [pscustomobject] $out
    }
}

After parsing the test.txt file with above switch, $parsed would look like this:

names company city   district country admin   tech  seller       status   id
----- ------- ----   -------- ------- -----   ----  ------       ------   --
Hadi  sample  Tehran 8        IR      Mahmoud Hamed sell@company Active   12456
John  sample  Tehran 8        IR      Doe     Hamed sell@company Disabled 12456

Now $parsed can be exported to structured data at ease with Export-Csv and imported back as objects with Import-Csv:

$parsed | Export-Csv parseddata.csv -NoTypeInformation
$csv = Import-Csv parseddata.csv

It can also be filtered very easily a filtering cmdlet such as Where-Object:

# this array of objects where the `country` property value is equal to "IR"
# AND this array of objects where the `names` property value is equal to "Hadi"
$parsed | Where-Object { $_.country -eq 'IR' -and $_.names -eq 'Hadi' }

Which results in:

names    : Hadi
company  : sample
city     : Tehran
district : 8
country  : IR
admin    : Mahmoud
tech     : Hamed
seller   : sell@company
status   : Active
id       : 12456
  • Related