DanBot
DanBot

Reputation: 121

Powershell Nested Replace

I am looping through multiple remote machines looking for a certain string to appear in a log file (other things are being collected from each device but for simplicity I've left that out). When I find them I want to return them and write to a central log, this is all working perfectly, except I want to tidy up the central log, by removing information from each string.

So I start with

  **28-Jan-2021 01:31:49,TCPServer.run(),3,JMX TCP Server running on 8085

But want to save to Central Log

   28-Jan-2021 01:31:349,JMX TCP 8085

And I can achieve this using the below, but surely there is a more succinct way to do this? (have played about with -Replace but no joy)

 $JMXString8085 = $JMXString8085.Replace("TCPServer.run(),3,","")
 $JMXString8085 = $JMXString8085.Replace("}","")
 $JMXString8085 = $JMXString8085.Replace(" Server running on","")

Upvotes: 0

Views: 272

Answers (4)

js2010
js2010

Reputation: 27473

You can "or" the patterns together in regex, backslashing the regex characters you want taken literally (at least the parentheses). You don't address the 2 stars at the beginning. The 2nd arg to -replace is null by default. There's no "}" in the input string.

$string = '**28-Jan-2021 01:31:49,TCPServer.run(),3,JMX TCP Server running on 8085'


[regex]::escape('TCPServer.run(),3,* Server running on')

TCPServer\.run\(\),3,\*\ Server\ running\ on


$string -replace 'TCPServer.run\(\),3,|\*| Server running on'

28-Jan-2021 01:31:49,JMX TCP 8085

Upvotes: 0

Veverke
Veverke

Reputation: 11368

Not a powershell guy, but I am using the one-liner below in my azure pipeline:

(Get-Content -path 'myFilePath' -Raw) -replace "text-to-replace-1","replacing-text-1" -replace "text-to-replace-2","replacing-text-2" | Set-Content 'myFilePath'

Nest as many -replace as you want.

Upvotes: 0

Lee_Dailey
Lee_Dailey

Reputation: 7479

here is yet another way to do the job. [grin]

what it does ...

  • assigns the string to a $Var
  • chains .Replace() to get rid of the asterisks and the "Server" phrase
  • splits on the , chars
  • takes the 1st & 4th items from that split
  • joins them into one string with , [comma then space] for a delimiter
  • assigns that to a new $Var
  • displays the results

the code ...

$InString = '**28-Jan-2021 01:31:49,TCPServer.run(),3,JMX TCP Server running on 8085'
$OutString = ($InString.Replace('**', '').Replace('Server running on ', '').Split(',')[0, 3]) -join ', '

$OutString

output ...

28-Jan-2021 01:31:49, JMX TCP 8085

Upvotes: 1

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174555

[...] surely there is a more succinct way to do this? (have played about with -Replace but no joy)

There is, and -replace can indeed help us here. -replace is a regex operator, it performs text replacement using regular expressions - patterns we can use to describe strings that we might not be quite sure the exact contents of.

For a string like:

$string = '**28-Jan-2021 01:31:49,TCPServer.run(),3,JMX TCP Server running on 8085'

... we could describe the fields in between the commas, and use that to tell PowerShell to only preserve some of them for example:

PS ~> $string -replace '^\*\*([^,]+),[^,]+,[^,]+,([^,]+) Server running on (\d+)', '$1,$2 $3'
28-Jan-2021 01:31:49,JMX TCP 8085

The pattern I used in this example (^\*\*([^,]+),[^,]+,[^,]+,([^,]+) Server running on (\d+)) might seem a bit alien at first, so let's try and break it down:

^                 # carret means "start of string"
 \*\*             # Then we look for two literal asterisks
 (                # This open parens means "start of a capture group"
  [^,]+           # This means "1 or more characters that are NOT a comma", captures the timestamp
 )                # And this matching closing parens means "end of capture group"
 ,                # Match a literal comma
 [^,]+            # Same as above, this one will match "TCPServer.run()"
 ,                # Same as above
 [^,]+            # You probably get the point by now
 ,                # ...
 (                # This open parens means "start ANOTHER capture group"
  [^,]+?          # The `?` at the end means "capture as few as possible", captures "JMX TCP"
 )                # And this matching closing parens still means "end of capture group"
  Server...       # Just match the literal string " Server running on "
 (                # Finally a THIRD capture group
  \d+             # capturing "1 or more digits", in your case "8085"
 )                # and end of group

Since our pattern "captures" a number of substrings, we can now refer to these individual substrings in out substition pattern $1,$2 $3, and PowerShell will replace the $N references with the capture group value.

Upvotes: 2

Related Questions