RegEx for Replace is kicking my butt. I am trying find:
value="COM8"/>
in a text file and replace "COM8" with another com port (ie "COM9", "COM13", etc).
(Get-Content 'C:\Path\File.config').Replace('/".*?"', '"COM99"') | Set-Content 'C:\Path\File.config'
Thank you in advance for any help you can provide.
Get-Content produces a list of strings. Replace() is called on each string via member enumeration. Meaning, you're calling the String.Replace() method, not the Regex.Replace() method. The former does only normal string replacements.
Use the -replace operator instead:
(Get-Content 'C:\Path\File.config') -replace '=".*?"', '="COM99"' |
Set-Content 'C:\Path\File.config'
Related
I made a Powershell script to update my mpv scripts. One of them being this
https://raw.githubusercontent.com/mpv-player/mpv/master/player/lua/osc.lua
I want the script to edit and remove all instances of show_message(get_playlist(), 3) from the file.
I tried (get-content .\Scripts\osc.lua) | foreach-object {$_ -replace "show_message(get_playlist(), 3)", ""} | Out-File .\Scripts\osc.lua and (get-content .\portable_config\Scripts\osc.lua) | foreach-object {String.Replace [RegEx]::Escape('show_message(get_playlist(), 3)'),''} | Out-File .\portable_config\Scripts\osc.lua but they dont seem to work.
Basically I want the script to automatically download osc.lua(which works fine as intended) and then remove all instances of show_message(get_playlist(), 3) from the file. My PowerShell version is 5.1.
You can use the following with the Replace Operator:
$regex = [regex]::Escape('show_message(get_playlist(), 3)')
(Get-Content .\Scripts\osc.lua) -replace $regex |
Set-Content .\Scripts\osc.lua
Alternatively, you can use the String.Replace method from the String class, which does not use regex.
(Get-Content .\Scripts\osc.lua).Replace('show_message(get_playlist(), 3)','') |
Set-Content .\Scripts\osc.lua
Explanation:
When using the -replace operator, the matching mechanism is a regex match. Certain characters are metacharacters for regex and must be escaped before they can be interpreted literally. In this case ( and ) need to be escaped. You can either do that manually with \ (\( and \)) or use the Escape() method from the Regex class. From the code above, you can type $regex after its declaration and see how it was escaped.
When replacing a string with an empty string, you do not need to specify a replacement string. 'String' -replace 'ing' has the same results as 'String' -replace 'ing',''
Note: You are mixing Get-Content and Out-File in your code without using the -Encoding parameter. It is possible you could output a different encoding than the original file. If this matters to you, I'd suggest using the -Encoding parameter with the appropriate encoding.
RegEx for Replace is kicking my butt. I am trying find:
value="COM8"/>
in a text file and replace "COM8" with another com port (ie "COM9", "COM13", etc).
(Get-Content 'C:\Path\File.config').Replace('/".*?"', '"COM99"') | Set-Content 'C:\Path\File.config'
Thank you in advance for any help you can provide.
Get-Content produces a list of strings. Replace() is called on each string via member enumeration. Meaning, you're calling the String.Replace() method, not the Regex.Replace() method. The former does only normal string replacements.
Use the -replace operator instead:
(Get-Content 'C:\Path\File.config') -replace '=".*?"', '="COM99"' |
Set-Content 'C:\Path\File.config'
I have a script that I need to replace a couple of lines in. The first replace is going fine but the second is wiping out my file and duplicating the line multiple times.
My code
(get-content $($sr)) -replace 'remoteapplicationname:s:SHAREDAPP',"remoteapplicationcmdline:s:$($sa)" | Out-File $($sr)
(get-content $($sr)) -replace 'remoteapplicationprogram:s:||SHAREDAPP',"remoteapplicationprogram:s:||$($sa)" | Out-File $($sr)
The first replace works perfectly. The second one is causing this:
remoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagarederemoteapplicationprogram:s:||stagareddremoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagarederemoteapplicationprogram:s:||stagaredcremoteapplicationprogram:s:||stagaredtremoteapplicationprogram:s:||stagaredcremoteapplicationprogram:s:||stagaredlremoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagaredpremoteapplicationprogram:s:||stagaredbremoteapplicationprogram:s:||stagaredoremoteapplicationprogram:s:||stagaredaremoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagareddremoteapplicationprogram:s:||stagared:remoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagared:remoteapplicationprogram:s:||stagared1remoteapplicationprogram:s:||stagared
etc...
Is this because of the ||? If so, how do I get around it?
Thanks!
To begin with, you should be using slightly more meaningful names for your variables. Especially if you want someone else to be reviewing your code.
The gist of your issue is that -replace supports regexes (regular expressions), and you have regex control characters in your pattern string. Consider the following simple example, and notice everywhere the replacement string is found:
PS C:\Users\Matt> "ABCD" -replace "||", "bagel"
bagelAbagelBbagelCbagelDbagel
-replace is also an array operator, so it works on every line of the input file, which is nice. For simplicity's sake, if you are not using a regex, you should just consider using the string method .Replace(), but it is case-sensitive, so that might not be ideal. So let's escape those control characters in the easiest way possible:
$patternOne = [regex]::Escape('remoteapplicationname:s:SHAREDAPP')
$patternTwo = [regex]::Escape('remoteapplicationprogram:s:||SHAREDAPP')
(get-content $sr) -replace $patternOne, "remoteapplicationcmdline:s:$sa" | Out-File $($sr)
(get-content $sr) -replace $patternTwo, "remoteapplicationprogram:s:||$sa" | Out-File $($sr)
Now we get both patterns matched as you have them written. Run $patternTwo on the console to see what has changed to it! $patternOne, as written, has no regex control characters in it, but it does not hurt to use the escape method if you are just expecting simple matching.
Aside from the main issue pointed out, there is also some redundancy and misconception that can be addressed here. I presume you are updating a source file to replace all occurrences of those strings, yes? Well, you don't need to read the file in twice, given that you can chain -replace:
$patternOne = [regex]::Escape('remoteapplicationname:s:SHAREDAPP')
$patternTwo = [regex]::Escape('remoteapplicationprogram:s:||SHAREDAPP')
(get-content $sr) -replace $patternOne, "remoteapplicationcmdline:s:$sa" -replace $patternTwo, "remoteapplicationprogram:s:||$sa" |
Set-Content $sr
Perhaps that will do what you intended.
You might notice that I've removed the subexpressions operators ($(...)) around your variables. While they have their place, they don't need to be used here. They are only needed inside more complicated strings, like when you need to expand object properties or something.
I'm trying to write a simple script that reads a file, locates a string, replaces the string with another string, and stores all new file contents (with replaced string), in a new file. Here is what I'm using:
(Get-Content C:\file1.txt) | {$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
The error I'm receiving is: "Expressions are only allowed as the first element of a pipeline"
I'm pretty sure this is because of the colon ":" character being in both the string I'm locating and replacing it with. I've tried escaping the colon character with "\" and "`" characters, but I'm receiving the same errors. Does anyone know what's wrong with this?
Thanks for the help.
The problem is the second element in your pipeline.
{$_ -replace "this:text", "withthis:text"}
This is a scriptblock (i.e. a piece of code). If you want to apply a scriptblock to all of the incoming items on a pipeline you can use the foreach-object cmdlet like this:
(Get-Content C:\file1.txt) | foreach-object {$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
#shagun is using the % alias for the foreach-object cmdlet, so that code looks correct as well.
I guess it is because after first pipe you are not processing each result. so the right one will be according to me :
(Get-Content C:\file1.txt) | %{$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
My text file looks like this.
"MikeCRLF","","","Dell","DevelCRLFCRLFoper"CRLF
"SuCRLFsan","","","Apple","ManagCRLFer"CRLF
Desired result:
"Mike","","","Dell","Developer"LF
"Susan","","","Apple","Manager"LF
I tried this on PowerShell:
"C:\Users\abc\Desktop\1.txt"
(Get-Content $path -Raw).Replace("`r`n","`n") | Set-Content $path -Force
When I do this, I don't get the desired result. Also, I am left with one CRLF at the end. I don't want that either.
Please tell me how to do this using PowerShell v3.
This method avoids checking to see if \r\n is in quotes. Instead, it tries to find the "real" end of line situations and converts those first. Then it just purges the rest.
(Get-Content test.txt -Raw) -replace '([^,]")(\s*\r\n\s*)+("[^,])',"`$1`n`$3" -replace '\r\n',''
I think this should handle most of the stuff you throw at it, but let me know if you find a special case.
edited to fix the replacement string
If you are using the PowerShell Community Extensions, you can use the ConvertTo-UnixLineEnding command e.g.:
ConvertTo-UnixLineEnding C:\users\abc\desktop1.txt -dest desktop1-converted.txt -Enc ascii