1
votes

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)"
2
Does this answer your question? Powershell, rename-item doesn't work as expectediRon

2 Answers

1
votes

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.

0
votes

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) }