Regex on Powershell script: Replace till end of line - regex

I have some config files structured like:
PATH_KEY=C:\\dir\\project
foo=bar
I want to write a small script that replaces a certain key with current folder.
So basically I'm trying to replace "PATH_KEY=..." with "PATH_KEY=$PSScriptRoot"
My code so far:
$cfgs = Get-Childitem $PSScriptRoot -Filter *name*.cfg
foreach ($cfg in $cfgs)
{
( Get-Content $cfg) -replace 'PATH_KEY=.*?\n','PATH_KEY=$PSScriptRoot' | Set-Content $cfg
}
But the regular expression to take everything till end of line is not working.
Any help is appreciated!

You can use
'(?m)^PATH_KEY=.*'
or even
'PATH_KEY=.*'
Note that $ in the replacement should be doubled to denote a single $, but it is not a problem unless there is a digit after it.
See the demo:

Related

How to replace lines depending on the remaining text in file using PowerShell

I need to edit txt file using PowerShell. The problem is that I need to apply changes for the string only if the remaining part of the string matches some pattern. For example, I need to change 'specific_text' to 'other_text' only if the line ends with 'pattern':
'specific_text and pattern' -> changes to 'other_text and pattern'
But if the line doesn't end with pattern, I don't need to change it:
'specific_text and something else' -> no changes
I know about Replace function in PowerShell, but as far as I know it makes simple change for all matches of the regex. There is also Select-String function, but I couldn't combine them properly. My idea was to make it this way:
((get-content myfile.txt | select-string -pattern "pattern") -Replace "specific_text", "other_text") | Out-File myfile.txt
But this call rewrites the whole file and leaves only changed lines.
You may use
(get-content myfile.txt) -replace 'specific_text(?=.*pattern$)', "other_text" | Out-File myfile.txt
The specific_text(?=.*pattern$) pattern matches
specific_text - some specific_text...
(?=.*pattern$) - not immediately followed with any 0 or more chars other than a newline as many as possible and then pattern at the end of the string ($).

find repetitive string in a file

I have a text file Data.txt of Size in few MBs.
It has repetitive lines like
VolumeTradingDate=2017-09-05T00:00:00.000 VolumeTotal=73147 LastTradeConditions=0 in key=value format.
There are various key=valuedata, for simplicity I am showing very few.
Values are changing in lines.
I want to search all occurrences of VolumeTotal with its value and print/dump only that part in separate lines. Its value can be upto 25 characters.
I tried using cmd FindStr
findstr /C:VolumeTotal= "C:\Work\Data.txt"
But this doesn't give me desired result. It prints entire line.
Could anyone suggest what could be possible script in cmd or powershell to achieve this?
You can do this in PowerShell with a RegEx that uses look ahead and look behind:
Get-Content Data.txt | ForEach-Object {
$Check = $_ -Match '(?<= VolumeTotal\=)\d*(?= )'
If ($Check) { $Matches.Values }
}
The pattern: (?<= VolumeTotal\=)\d*(?= ) looks for any number of digits \d* between the strings ' VolumeTotal=' and a space character.
The result is sent to the automatic variable $Matches so we return the value of this variable if the pattern has been found.

How to trim the file modification value from SVN log output with PowerShell

I have an SVN log being captured in PowerShell which I am then trying to modify and string off everything except the file URL. The problem I am having is getting a regex to remove everything before the file URL. My entry is matched as:
M /trunk/project/application/myFile.cs
There are two spaces at the beginning which originally I was trying to replace with a Regex but that did not seem to work, so I use a trim and end up with:
M /trunk/project/application/myFile.cs
Now I want to get rid of the File status indicator so I have a regular expression like:
$entry = $entry.Replace("^[ADMR]\s+","")
Where $entry is the matched file URL but this doesn't seem to do anything, even removing the caret to just look for the value and space did not do anything. I know that $entry is a string, I originally thought Replace was not working as $entry was not a string, but running Get-Member during the script shows I have a string type. Is there something special about the svn file indicator or is the regex somehow off?
Given your example string:
$entry = 'M /trunk/project/application/myFile.cs'
$fileURL = ($entry -split ' /')[1]
Your regex doesn't work because string.Replace just does a literal string replacement and doesn't know about regexes. You'd probably want [Regex]::Replace or just the -replace operator.
But when using SVN with PowerShell, I'd always go with the XML format. SVN allows a --xml option to all commands which then will output XML (albeit invalid if it dies in between).
E.g.:
$x = [xml](svn log -l 3 --verbose --xml)
$x.log.logentry|%{$_.paths}|%{$_.path}|%{$_.'#text'}
will give you all paths.
But if you need a regex:
$entry -replace '^.*?\s+'
which will remove everything up to (and including) the first sequence of spaces which has the added benefit that you don't need to remember what characters may appear there, too.

PowerShell - Replace contents of every tag using REGEX

I am trying to write a PowerShell script to replace the contents of tags i have put into an XML file. The tags appear multiple times within the XML, this is resulting in everything between the first and last tag being replaced as it is not stopping the first time the end tag is found.
I am using this:
$NewFile = (Get-Content .\myXML_file.xml) -join "" | foreach{$_ -replace "<!--MyCustom-StartTag-->(.*)<!--MyCustom-EndTag-->","<!--MyCustom-StartTag-->New Contents of Tag<!--MyCustom-EndTag-->"};
Set-Content .\newXMLfile.xml $newfile;
The file has contents like:
<!--MyCustom-StartTag-->
Lots of content
<!--MyCustom-EndTag-->
More stuff here
<!--MyCustom-StartTag-->
Lots of content
<!--MyCustom-EndTag-->
And i am ending up with:
<!--MyCustom-StartTag-->
New Content Here
<!--MyCustom-EndTag-->
Instead of:
<!--MyCustom-StartTag-->
New content
<!--MyCustom-EndTag-->
More stuff here
<!--MyCustom-StartTag-->
New content
<!--MyCustom-EndTag-->
I have tried using: (?!MyCustom-StartTag) but that does work either.
Any ideas of what i should do to get this to work.
Thanks,
Richard
You should use the non-greedy version of *, namely *?. For more info, see: http://www.dijksterhuis.org/csharp-regular-expression-operator-cheat-sheet/ (Powershell uses same regex engine as C#).
$NewFile = (Get-Content .\myXML_file.xml) -join "" | foreach{$_ -replace "<!--MyCustom-StartTag-->(.*?)<!--MyCustom-EndTag-->","<!--MyCustom-StartTag-->New Contents of Tag<!--MyCustom-EndTag-->"};
Set-Content .\newXMLfile.xml $newfile;
I think the reason that you are left with just a single pair of start and end tags is because your query pattern finds three matches in the search string.
The first pair of start and end.
The second pair of start and end.
The start from the first one, and the end tag from the second one (and if this match is found last, it will in fact replace all thats between the first and last with the new value).
So in your "(.*)" you might have to exclude any other start and end tags?

Text manipulation problem - how to replace text after a known value

I have a large text file containing filenames ending in .txt
Some of the rows of the file have unwanted text after the filename extension.
I am trying to find a way to search+replace or trim the whole file so that if a row is found with .txt, anything after this is simply removed. Example
C:\Test1.txt
C:\Test2.txtHelloWorld this is my
problem
C:\Test3.txt_____Annoying
stuff1234 .r
Desired result
C:\Test1.txt
C:\Test2.txt
C:\Test3.txt
I have tried with notepad++, or using batch/powershell, but got close, no cigar.
(Get-Content "D:\checkthese.txt") |
Foreach-Object {$_ -replace '.txt*', ".txt"} |
Set-Content "D:\CLEAN.txt"
My thinking here is if I replace anything (Wildcard*) after .txt then I would trim off what I need, but this doesnt work. I think I need to use regular expression, buy have the syntax wrong.
Simply change the * to a .*, like so:
(Get-Content "D:\checkthese.txt") |
Foreach-Object {$_ -replace '\.txt.*', ".txt"} |
Set-Content "D:\CLEAN.txt"
In regular expressions, * means "0 or more times", and in this case it'd act on the final t of .txt, so .txt* would only match .tx, .txt, .txtt, .txttt, etc...
., however, matches any character. This means, .* matches 0 or more of anything, which is what you want. Because of this, I also escaped the . in .txt, as it otherwise could break on filenames like: alovelytxtfile.txt, which would be trimmed to alovel.txt.
For more information, see:
Regex Tutorial - .
Regex Tutorial - *