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-Content
does by default. Use the-Raw
switch 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
-replace
operator 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-replace
vs.[string]::Replace()
- In Windows PowerShell
The search string must be escaped with
[regex]::Escape()
, so that the .NET regex engine, which the-replace
operator 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
-replace
works, 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
\n
escape sequence in$reSearch
with\r?\n
($reSearch = $reSearch.Replace('\n', '\r?\n')
and possibly replace the literal newline in$substitution
with`r`n
or`n
, as needed.