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