Select 2 lines from multiline

This topic contains 5 replies, has 3 voices, and was last updated by Profile photo of deiandrei deiandrei 3 years, 5 months ago.

  • Author
    Posts
  • #11140
    Profile photo of deiandrei
    deiandrei
    Participant

    Hi there,

    I have a very large text file, from which I extract some strings and store them in a variable $a.
    That variable $a looks like:
    2013/09/20 16:45:59.285 [009] Collect finished
    2013/09/23 08:17:58.678 [009] *** Collect CMI commands for system
    2013/09/23 08:18:03.561 [009] Collect finished
    2013/09/23 08:19:39.878 [023] Collect finished
    2013/09/24 08:16:42.238 [009] *** Collect CMI commands for system
    2013/09/24 08:16:49.430 [009] Collect finished
    2013/09/24 08:17:53.052 [009] *** Collect CMI commands for system
    2013/09/24 08:17:57.058 [009] Collect finished
    2013/09/24 08:18:20.987 [023] Collect finished
    2013/09/25 08:27:50.636 [009] *** Collect CMI commands for system
    2013/09/25 08:27:59.528 [009] Collect finished
    2013/09/25 08:45:12.290 [009] *** Collect CMI commands for system
    2013/09/25 08:45:17.142 [009] Collect finished
    2013/09/25 08:47:17.060 [023] Collect finished

    Now I would like to somehow select only the lines containing the text "Collect CMI commands for system" together with the very next line.
    So my goal is to obtain this:
    2013/09/23 08:17:58.678 [009] *** Collect CMI commands for system
    2013/09/23 08:18:03.561 [009] Collect finished
    2013/09/24 08:16:42.238 [009] *** Collect CMI commands for system
    2013/09/24 08:16:49.430 [009] Collect finished
    2013/09/24 08:17:53.052 [009] *** Collect CMI commands for system
    2013/09/24 08:17:57.058 [009] Collect finished
    2013/09/25 08:27:50.636 [009] *** Collect CMI commands for system
    2013/09/25 08:27:59.528 [009] Collect finished
    2013/09/25 08:45:12.290 [009] *** Collect CMI commands for system
    2013/09/25 08:45:17.142 [009] Collect finished

    I tried regular expressions, but I can't figure out how to use the carriage return character.
    This is what I tried:
    $regex = ".*Collect CMI commands for system.*(\r.*)"
    $a -match $regex

    That regular expression should return the line containing the specific text and its consecutive line.

    But this doesn't return anything...

    Well, then I thought that this text is not really a string, but it's an array. Still, how can I filter the array to obtain the same text I already mentioned?

    Thank you!

  • #11141
    Profile photo of deiandrei
    deiandrei
    Participant

    Alright, I did some further troubleshooting and realized this is indeed an array.
    So, how can I get the index of an element containing "Collect CMI commands for system"?
    My way of thinking is: Get the index of that element, add +1 to the index and return both elements.
    I tried already:
    [array]::IndexOf($a,"*Collect finished*")
    but this returns -1 (maybe because there are multiple such lines?)

  • #11143
    Profile photo of deiandrei
    deiandrei
    Participant

    I think I figured it out:
    So, $a was my array of lines.
    $regex = ".*Collect CMI commands for system.*"
    $b = 0..($a.Count – 1) | where {$a[$_] -match $regex}
    foreach ($item in $b) {$a[$item],$a[$item + 1]}

    This will return me exactly what I wanted:
    2013/09/23 08:17:58.678 [009] *** Collect CMI commands for system
    2013/09/23 08:18:03.561 [009] Collect finished
    2013/09/24 08:16:42.238 [009] *** Collect CMI commands for system
    2013/09/24 08:16:49.430 [009] Collect finished
    2013/09/24 08:17:53.052 [009] *** Collect CMI commands for system
    2013/09/24 08:17:57.058 [009] Collect finished
    2013/09/25 08:27:50.636 [009] *** Collect CMI commands for system
    2013/09/25 08:27:59.528 [009] Collect finished
    ........................................

    Thank you guys for your time!

  • #11144
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Another way you can accomplish this is with the -Context parameter to Select-String. For example:

    $a | Select-String -Pattern '.*Collect CMI Commands for system.*' -Context 1 |
    ForEach-Object {
        $_.Matches[0].ToString()
        $_.Context.PostContext[0]
    }
    
  • #11164
    Profile photo of Joakim Svendsen
    Joakim Svendsen
    Participant

    Here's a regex solution:


    #PS E:\temp> $a = gc .\data-cmi.txt # the example date pasted into a file
    #PS E:\temp> $a = $a -join "`n" # create a one-line string from the array
    #PS E:\temp> $a = $a -replace '\r', '' # just to be safe, they're not needed anyway
    #PS E:\temp> [regex]::Matches($a, '([^\n]+ Collect CMI commands for system[^\n]*\n[^\n]+)') | %{ $_.Value }
    #2013/09/23 08:17:58.678 [009] *** Collect CMI commands for system
    #2013/09/23 08:18:03.561 [009] Collect finished
    #2013/09/24 08:16:42.238 [009] *** Collect CMI commands for system
    #2013/09/24 08:16:49.430 [009] Collect finished
    #2013/09/24 08:17:53.052 [009] *** Collect CMI commands for system
    #2013/09/24 08:17:57.058 [009] Collect finished
    #2013/09/25 08:27:50.636 [009] *** Collect CMI commands for system
    #2013/09/25 08:27:59.528 [009] Collect finished
    #2013/09/25 08:45:12.290 [009] *** Collect CMI commands for system
    #2013/09/25 08:45:17.142 [009] Collect finished

  • #11168
    Profile photo of deiandrei
    deiandrei
    Participant

    thank you all! your suggestions are more than welcome!

You must be logged in to reply to this topic.