1

I am trying to substitute both regex and an environment variable and can't find the correct syntax (because of the mismatch of single and double quotes). The short script I am developing will rename files. Here is what my setup looks like a few of the ways I tried.

# Original File Name: (BRP-01-001-06K48b-SC-CC-01).tif
# Desired File Name:  (BRP-12-345-06K48b-SC-CC-01).tif

# Variables defined by user:
PS ..\user> $pic,$change="01-001","12-345"

# The problem is with the "-replace" near the end of the command
PS ..\user> get-childitem .\* -recurse | where-object {$_.BaseName -match ".*\(BRP-$pic-.{15}\).*"} | foreach-object {$orig=($_.FullName); $new=($orig -replace "(\(BRP-)($pic)(-.{15}\))", '$1$change$3'); echo $new}
PS ..\user> (BRP-$change-06K48b-SC-CC-01).tif

# Also tried:
PS ..\user> get-childitem .\* -recurse | where-object {$_.BaseName -match ".*\(BRP-$pic-.{15}\).*"} | foreach-object {$orig=($_.FullName); $new=($orig -replace "(\(BRP-)($pic)(-.{15}\))", "`$1$change`$3"); echo $new}
PS ..\user> $112-345-06K48b-SC-CC-01).tif

# If I put a space before $change:
PS ..\user> get-childitem .\* -recurse | where-object {$_.BaseName -match ".*\(BRP-$pic-.{15}\).*"} | foreach-object {$orig=($_.FullName); $new=($orig -replace "(\(BRP-)($pic)(-.{15}\))", "`$1 $change`$3"); echo $new}
PS ..\user> (BRP- 12-345-06K48b-SC-CC-01).tif

In the last example it "works" if I add space before $change ... but I do not want the space. I realize I could do another replace operation to fix the space but I would like to do this all in one command if possible.

What syntax do I need to replace using both environment variables and regex substitutions?

Also, out of curiosity, once working, will this replace all occurrences within a file name or just the first. For instance, will the file:

"Text (BRP-01-001-06K48b-SC-CC-01) Text (BRP-01-001-06K48b-SC-OR-01)"

change to:

"Text (BRP-12-345-06K48b-SC-CC-01) Text (BRP-12-345-06K48b-SC-OR-01)"

or only the first match, like:

"Text (BRP-12-345-06K48b-SC-CC-01) Text (BRP-01-001-06K48b-SC-OR-01)"
Brian
  • 179
  • 7
  • Does this answer your question? [Powershell, rename-item doesn't work as expected](https://stackoverflow.com/questions/42470793/powershell-rename-item-doesnt-work-as-expected) – iRon Jun 23 '20 at 09:01

2 Answers2

1

Best practice is surrounding your capture group name in {} or using named capture groups within your substitution string. Using {} with your second example, should work out nicely.

"Text (BRP-01-001-06K48b-SC-CC-01) Text (BRP-01-001-06K48b-SC-OR-01)" -replace "(\(BRP-)($pic)(-.{15}\))", "`${1}$change`${3}"

When PowerShell variables, capture groups, and string literals are in the replacement string, you can't use surrounding single quotes. Using surrounding double quotes allows inner expansion to happen. As a result, you will need to backtick escape $ used to identify capture groups.

Your second example has the proper syntax, typically, but because $change begins with digits, it creates unintended consequences. You are escaping $ in the substitution string to use capture groups 1 and 3. Since $change evaluates to 12-345, the intended capture group 1 is actually capture group 112, which doesn't exist. See below for an illustration of your second attempt:

"(\(BRP-)($pic)(-.{15}\))":

  • Capture Group 1: (BRP-
  • Capture Group 2: 01-001
  • Capture Group 3: -06K48b-SC-CC-01)

"`$1$change`$3" at runtime becomes $112-345$3 and then becomes $112-345-06K48b-SC-CC-01). Notice that $112 has been interpolated before the capture groups are substituted. Then capture group 112 is checked. Since it does not exist, $112 is just assumed to be a string.

AdminOfThings
  • 23,946
  • 4
  • 17
  • 27
0

The below might be what you are after,

$pic = "01-001"
$change = "12-345"
$RenameFiles_FilterStr = "*BRP-$pic*.tif"

gci $RenameFiles_FilterStr -recurse | % { $_.BaseName -replace $pic,$change }

# The above returns renamed strings (files not renamed yet). If the expected result matches the returned ones, then uncomment the below and run to rename the files
# gci $RenameFiles_FilterStr -recurse | % { Rename-Item -NewName ($_.BaseName -replace $pic,$change) }
Karthick Ganesan
  • 375
  • 4
  • 11
  • Thanks for this. While the actual problem I am working on has more complexities that require the flexibility of Regex substitutions, I really like the concise solution you provided (as it solves the problem as I presented it). There have been many times when I could have used a simpler solution like yours and I anticipate I will find use for this often in the future outside my current project. It is really quite elegant in its simplicity – Brian Jun 26 '20 at 05:58