How do you use a variable in a regex replace statement [duplicate] - regex

$file = 'c:\temp\config.ini'
# login.ruby.authentication.key=eskimopie
$pattern = [regex] "(.*?login\.ruby\.authentication\.key)=(.*?).*"
$secret = '12345678'
$text = (Get-Content -Path c:\temp\config.ini)
$value = $text -match "$pattern"
$text -replace "$pattern",'$1=$secret' | Set-Content config.new
The problem is it replaces the line with
login.ruby.authentication.key)=$secret (in that, it actually puts $secret instead of 12345678. I am looking for how to get this to put the value of $secret instead of the word $secret.

When used inside single quoted literals, variables do not get expanded. You need to use double quoted string literal that allows string interpolation.
However, the first $ should not be expanded. To tell PS not to interpolate it, add a backtick before it. See about_Quoting_Rules:
To prevent the substitution of a variable value in a double-quoted string, use the backtick character (`)(ASCII 96), which is the Windows PowerShell escape character.
So, replace with "`$1=$secret" where `$1 will pass a literal $1 string to the regex engine, and $secret will get interpolated to 12345678 before passing it to the regex engine.

Related

PowerShell regex does not match near newline

I have an exe output in form
Compression : CCITT Group 4
Width : 3180
and try to extract CCITT Group 4 to $var with PowerShell script
$var = [regex]::match($exeoutput,'Compression\s+:\s+([\w\s]+)(?=\n)').Groups[1].Value
The http://regexstorm.net/tester say, the regexp Compression\s+:\s+([\w\s]+)(?=\n) is correct but not PowerShell. PowerShell does not match. How can I write the regexp correctly?
You want to get all text from some specific pattern till the end of the line. So, you do not even need the lookahead (?=\n), just use .+, because . matches any char but a newline (LF) char:
$var = [regex]::match($exeoutput,'Compression\s+:\s+(.+)').Groups[1].Value
Or, you may use a -match operator and after the match is found access the captured value using $matches[1]:
$exeoutput -match 'Compression\s*:\s*(.+)'
$var = $matches[1]
Wiktor Stribiżew's helpful answer simplifies your regex and shows you how to use PowerShell's -match operator as an alternative.
Your follow-up comment about piping to Out-String fixing your problem implies that your problem was that $exeOutput contained an array of lines rather than a single, multiline string.
This is indeed what happens when you capture the output from a call to an external program (*.exe): PowerShell captures the stdout output lines as an array of strings (the lines without their trailing newline).
As an alternative to converting array $exeOutput to a single, multiline string with Out-String (which, incidentally, is slow[1]), you can use a switch statement to operate on the array directly:
# Stores 'CCITT Group 4' in $var
$var = switch -regex ($exeOutput) { 'Compression\s+:\s+(.+)' { $Matches[1]; break } }
Alternatively, given the specific format of the lines in $exeOutput, you could leverage the ConvertFrom-StringData cmdlet, which can perform parsing the lines into key-value pairs for you, after having replaced the : separator with =:
$var = ($exeoutput -replace ':', '=' | ConvertFrom-StringData).Compression
[1] Use of a cmdlet is generally slower than using an expression; with a string array $array as input, you can achieve what $array | Out-String does more efficiently with $array -join "`n", though note that Out-String also appends a trailing newline.

powershell regex displaying variable name instead of its value during replace

$file = 'c:\temp\config.ini'
# login.ruby.authentication.key=eskimopie
$pattern = [regex] "(.*?login\.ruby\.authentication\.key)=(.*?).*"
$secret = '12345678'
$text = (Get-Content -Path c:\temp\config.ini)
$value = $text -match "$pattern"
$text -replace "$pattern",'$1=$secret' | Set-Content config.new
The problem is it replaces the line with
login.ruby.authentication.key)=$secret (in that, it actually puts $secret instead of 12345678. I am looking for how to get this to put the value of $secret instead of the word $secret.
When used inside single quoted literals, variables do not get expanded. You need to use double quoted string literal that allows string interpolation.
However, the first $ should not be expanded. To tell PS not to interpolate it, add a backtick before it. See about_Quoting_Rules:
To prevent the substitution of a variable value in a double-quoted string, use the backtick character (`)(ASCII 96), which is the Windows PowerShell escape character.
So, replace with "`$1=$secret" where `$1 will pass a literal $1 string to the regex engine, and $secret will get interpolated to 12345678 before passing it to the regex engine.

Use Variable in Replace

I have a text file and want to regex/replace something with the content of a variable in PowerShell.
File: my.json
Variable in Powershell $version
Search for: version : "something"
Replace "something" with the content of the variable $version
Here is what I tried. Search and replace works as expected but the result is
version : "$version".
(Get-Content my.json) -replace '(?<pre>"version"[\s]*:[\s]*)(?<V>"[^\"]*")', '$1"$version"' | Out-File my.json
To be able to use variables in the replacement string you need to use a double-quoted replacement string, meaning that you need to escape backreferences and nested double quotes:
(Get-Content my.json) -replace '...', "`$1`"$version`"" | ...
Ansgar's answer is perfectly valid, but ` escape sequences can be ugly and hinder readability.
I would personally use the -f format operator to concatenate the '$1' string literal and the value of $version:
(Get-Content my.json) -replace '...',('$1{0}' -f $version)

How to use $_ in content without been replaced by powershell?

I'm trying to replace a word to some php code
$filecontent = [regex]::Replace($filecontent, $myword, $phpcode)
But the $phpcode have some php code using also a Special variable $_
<?php $cur_author = (isset($_GET['author_name'])) ? get_user_by('slug', $author_name) : get_userdata(intval($author)); ?>
The problem is when the code is replace in $filecontent it replaces the $_ variable from the php code ( $_GET ) with it have on the pipeline.
This not happen with the other variables like $author_name .
How can I resolve this?
Does this work for you?
$filecontent = [regex]::Replace($filecontent, $myword, {$phpcode})
In a regex replace operation the $_ is a reserved substituion pattern that represents the entire string
http://msdn.microsoft.com/en-us/library/az24scfc.aspx
Wrapping it in braces makes it a scriptblock delegate, bypassing the normal regex pattern matching algorithms for doing the replacement.
You have two options. First use a single quoted string and PowerShell will treat that as a verbatim string (C# term) i.e. it won't try to string interpolate:
'$_ is passed through without interpretation'
The other option is to escape the $ character in a double quoted string:
"`$_ is passed through without interpretation"
When I'm messing with a regex I will default to using single quoted strings unless I have a variable that needs to be interpolated inside the string.
Another possibility is that $_ is being interpreted by regex as a substitution group in which case you need to use the substitution escape on the $ e.g. $$.
Im not sure I am following you correctly, but does this help?
$file = path to your file
$oldword = the word you want to replace
$newword = the word you want to replace it with
If the Oldword you are replacing has special charactes ( ie. \ or $ ) then you must escape them first. You can escape them by putting a backslash in front of the special character. The Newword, does not need to be escaped. A $ would become "\$".
(get-content $file) | foreach-object {$_ -replace $oldword,$NewWord} | Set-Content $file

How to ignore escape sequences stored in PowerShell string variable?

In my PowerShell script, I'm running Select-String over a number of files, looking for a string passed into it via a variable ($id):
foreach ($file in (ls "path\to\files")) {
$found = $false
$found = Select-String -Path $file $id -Quiet
if ($found) {
break
}
}
Unfortunately, the $id variable sometimes things like "\C" or "\T", which Select-String tries to interpret as escape sequences. These are not valid escape sequences, so Select-String throws an error. They are not intended to be escape sequences (e.g., it could be part of a file path such as "C:\Test"), so how can I prevent PowerShell/Select-String from interpreting them as such? I've tried using parentheses around $id with no luck.
Use the static escape() method, it instructs the regular expression engine to interpret these characters literally rather than as metacharacters:
$id = [regex]::escape($id)
You can also turn the command to a one liner (-path can take a collection of files):
Select-String -Path path\to\files\\* -Pattern ([regex]::escape($id)) -Quiet
Select-String has a -SimpleMatch parameter that will cause the cmdlet to do simple string matches instead of regular expressions. If you change the script to do:
$found = Select-String -Path $file $id -Quiet -SimpleMatch
it should work as desired.
If the $id string already contains something like TAB when it's passed to you then I'm not aware of a built in method to safely escape it back to "\t". You need to make sure your script is passed the correct string in the first place. I.e. it needs to passed 0x5C74 (\t) not 0x09 (TAB). So the escaping needs to be done when the the search string is first defined.
Regex.Escape will escape TAB -> \t but will also escape any of these characters that have meaning within regular expressions:
\, *, +, ?, |, {, [, (,), ^, $,., #, and white space
e.g. . -> \.