0

I have got a file "servers.txt" :

[Server1] 
Value_A 
Value_B 
Value_C

[Server2] 
Value_A

[Server3] 
Value_A 
Value_B 
Value_C 
Value_D

===

I need to search into this file and display the server line + all his values. Something like :

$search = "server3" 
gc servers.txt | Select-String -Pattern $search and diplay until the next "["

(I can't tell for example, display the line+1, because the values are different, sometimes there are only 3, sometimes 1, etc.)

Thanks a lot!

expirat001
  • 2,125
  • 4
  • 30
  • 40
  • Your file format is very similar to INI files. You should be able to adapt JPBlanc's solution [here](http://stackoverflow.com/a/20535228/1001100). – JamesQMurphy Jun 17 '14 at 17:38

2 Answers2

3

How about:

$search = "server3" 
(gc servers.txt -Delimiter '[') -like  "$search]*" -replace '^','[' -replace '\s*\[$'

Cleaner solution (I think):

(gc servers.txt -raw) -split '\r\n(?=\[)' -like "?$search]*" 
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • Good but this would add an extra '[' line at the end if we wanted [Server 2] section for example. And since we use `-replace` anyway: `$regex = '(?s).*(\[Server3\][^[]*).*'; (gc servers.txt | out-string) -replace $regex, '$1'` – Alexander Obersht Jun 17 '14 at 18:47
  • It will be a multi-line string (not a string array). The ^ will only anchor at the beginning of the server name. The -Delimiter is going to remove that first [ before the server name. The -Replace is just there to put it back. – mjolinor Jun 17 '14 at 18:54
  • Thanks! That's works but yes, it displays "[" at the end, how can I remove this? – expirat001 Jun 17 '14 at 19:11
  • I just replied at the bottom of this topic, I think the most easy is to remove the last line from variable, but I don't how to do that. – expirat001 Jun 17 '14 at 19:29
  • Updated. Not as clean as I'd like, but should work. – mjolinor Jun 17 '14 at 19:31
  • Add another solution that's a bit cleaner. – mjolinor Jun 17 '14 at 19:40
  • The cleaner solution looks intriguing. I understand what it does (or so I think). `(?=\[)` is a neat trick but why does it work? Is it documented anywhere? – Alexander Obersht Jun 18 '14 at 20:18
  • 1
    It's called a "Positive lookahead". Basically it says "split on any newline that is immediately followed by [ character. Only the newline is the split character. The (?=\[) simply qualifies which newlines will be used to split without making the [ part of the split characters, so the [ remains with the data. – mjolinor Jun 18 '14 at 21:08
2

Looks like your delimiter is a blank line. How about reading the file and processing it so the first line is server name, all the following lines until a blank are an array of data, and then on blank lines it outputs a custom object with the server name and array of data as properties, and creating an array of those object?

Hm, that's confusing, and I wrote it. Let me post code, and then explain it.

$Server = ""
$Data = @()
$Collection = @()
Switch(GC C:\temp\test.txt){
    {[String]::IsNullOrEmpty($Server) -and !([String]::IsNullOrWhiteSpace($_))}{$Server = $_;Continue}
    {!([String]::IsNullOrEmpty($Server)) -and !([String]::IsNullOrEmpty($_))}{$Data+=$_;Continue}
    {[String]::IsNullOrEmpty($_)}{$Collection+=[PSCustomObject]@{Server=$Server;Data=$Data};Remove-Variable Server; $Data=@()}
}
If(!([String]::IsNullOrEmpty($Server))){$Collection+=[PSCustomObject]@{Server=$Server;Data=$Data};Remove-Variable Server; $Data=@()}

Ok, it starts out by defining variables as either empty strings or arrays.

Then it processes each line, and performs one of three actions depending on the situation. The first line of the switch reads the text file, and processes it line by line. The first option in the Switch basically reads:

If there is nothing stored in the $Server variable, and the current line is not blank, then $Server = Current Line. Continue to the next line.

The second option is:

If $Server is not blank, and the current line is not blank, add this line to the array $Data. Continue to the next line.

The last option for the Switch is:

If the current line is blank, then this is the end of the current record. Create a custom object with two properties. The first property is named Server, and the value is whatever is in $Server. The second property is named Data, and the value is whatever is in $Data. Then remove the $server variable, and reset $Data to an empty array.

After the switch it checks to see if $Server still has data, and outputs one last object if it does. I do this in case there is no blank line at the end of the last record, just as cleanup.

What you are left with is $Collection being an array of objects that looks something like this:

Server                                             Data                                             
------                                             ----                                             
[Server1]                                          {Value_A , Value_B , Value_C}                    
[Server2]                                          {Value_A}                                        
[Server3]                                          {Value_A , Value_B , Value_C , Value_D}
TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56