I need to replace
location ~* "^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:32583;
by
location ~* "^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:$proxy;
I'm trying to achieve this with the following code with no success
Get-ChildItem 'C:\nginx\conf\nginx.conf' | ForEach {
(Get-Content $_) | ForEach {$_ -Replace "location ~\* \""^/\(888888-localhost\\/client\)(.*)$"" {
proxy_pass https://localhost:. ;", "location ~* ""^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:$proxy;""} | Set-Content $_
}
How can i do this using Powershell?
CodePudding user response:
One solution would be to use a positive lookbehind to ensure the pattern is matched:
@"
location ~* "^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:32583;
"@ -replace "(?<=\/localhost:)\d ",'$port'
# In your use-case
(Get-Content -Path ($Path = 'C:\nginx\conf\nginx.conf')) -replace "(?<=\/localhost:)\d ",'$port' |
Set-Content -Path $Path
Removing the single quotes around $port, or replacing them with double quotes will allow the use of $port as an actual variable.
CodePudding user response:
Since you want to match across lines, you cannot use the line-by-line processing that
Get-Contentdoes by default. Use the-Rawswitch to read the entire file at once, into a single, multi-line string.Since both your search string and the replacement string passed to the regex-based
-replaceoperator contain metacharacters, you must escape them.Note: If all you need is literal (verbatim) substring matching, including not needing to assert where the substring must match (start of the string, word boundary, ...), using
[string]::Replace()is the simpler option, however:- In Windows PowerShell
[string]::Replace()is invariably, case-sensitive, in PowerShell (Core) 7 it is by default, unlike PowerShell's operators - see this answer for guidance on when to use-replacevs.[string]::Replace()
- In Windows PowerShell
The search string must be escaped with
[regex]::Escape(), so that the .NET regex engine, which the-replaceoperator invariably uses, treats it as a literal.The substitution string must have any embedded
$characters escaped as$$, so that$isn't mistaken for the start of a capture-group reference.For a comprehensive overview of how
-replaceworks, see this answer.
# Escape the search string.
$reSearch = [regex]::Escape(@'
location ~* "^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:32583;
@')
# Escape the substitution string.
$substitution = @"
location ~* "^/(888888-localhost\/client)(.*)$" {
proxy_pass https://localhost:$proxy;
"@.Replace('$', '$$')
# ...
($_ | Get-Content -Raw) -replace $reSearch, $substitution |
Set-Content -LiteralPath $_.FullName
# ...
Note the use of both verbatim and expandable here-strings to facilitate declaring the strings.
As for a potential simplification of your -replace operation:
Abraham Zinala points out that ultimately you're looking to only replace the port number in the matched substring, so you could use a positive look-behind assertion (
(?<=...)), as shown in this simplified example:$proxy = 8080 'a https://localhost:80; z' -replace '(?<=https://localhost:)\d ', $proxy- Output is:
a https://localhost:8080; z
- Output is:
Caveat re newlines:
The above assumes that your script file uses the same newline format (Windows-format CRLF vs. Unix-format LF) as the input file.
If you're not sure, and you want to match either format, replace the
\nescape sequence in$reSearchwith\r?\n($reSearch = $reSearch.Replace('\n', '\r?\n')and possibly replace the literal newline in$substitutionwith`r`nor`n, as needed.
