Home > Mobile >  How do I use variables with the -replace Operator?
How do I use variables with the -replace Operator?

Time:08-02

I'm rather new to powershell, and I have been trying to make a script that takes all files in a directory with numbers in the title and renames them according to a template.

My Script looks like such:

$NewObjName = "My New Name"

cd E:\Test

dir | ren -NewName {$_.name -replace '([a-zA-Z])([a-zA-Z])\.(\d?)(\d).*','0$3$4'}
dir | ren -NewName {$_.name -replace '(\d?)(\d)(\d)',{Part $2$3 $NewObjName.txt}}

and does this:

PS E:\Test> ls


    Directory: E:\Test


Mode                 LastWriteTime         Length Name                                                                                                                                            
----                 -------------         ------ ----                                                                                                                                            
-a----          8/1/2022   2:14 PM              0 AB.01CDE                                                                                                                                        
-a----          8/1/2022   2:15 PM              0 AB.02CDE                                                                                                                                        
-a----          8/1/2022   2:15 PM              0 AB.10CDE                                                                                                                                        
-a----          8/1/2022   2:15 PM              0 AB.11CDE                                                                                                                                        



PS E:\Test> E:\RenameScript.ps1

PS E:\Test> ls


    Directory: E:\Test


Mode                 LastWriteTime         Length Name                                                                                                                                            
----                 -------------         ------ ----                                                                                                                                            
-a----          8/1/2022   2:14 PM              0 Part 01 $NewObjName.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 02 $NewObjName.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 10 $NewObjName.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 11 $NewObjName.txt                                                                                                                         



PS E:\Test> 

So it just puts in the variable name instead of the value of the variable. I'm not sure if -replace doesn't allow variables other than regex groupings or if I'm just missing something?

Thanks in advance :)

Edit: My expected result would be something like:

PS E:\Test> ls


    Directory: E:\Test


Mode                 LastWriteTime         Length Name                                                                                                                                            
----                 -------------         ------ ----                                                                                                                                            
-a----          8/1/2022   2:14 PM              0 Part 01 My New Name.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 02 My New Name.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 10 My New Name.txt                                                                                                                         
-a----          8/1/2022   2:15 PM              0 Part 11 My New Name.txt    

CodePudding user response:

$_.name -replace '(\d?)(\d)(\d)',{Part $2$3 $NewObjName.txt}

  • { ... } is a script-block literal, not a string literal.

    • When a script block is used in a context where it is coerced to a string, such as in your case, its verbatim content (sans { and }) is used. Therefore, $NewObjName was not expanded (interpolated).

      • While it can be convenient to use { ... } in lieu of an actual string literal in order to avoid the need for escaping of embedded quoting, it is best avoided in the interest of conceptual clarity.
    • As an aside: In PowerShell (Core) 6.1 , script blocks are now supported as the replacement operand of the -replace operator, albeit as script blocks, i.e. they provide a piece of code to run for a each match in order to dynamically determine the replacement text - see this answer for an example.

  • Since you need string expansion (interpolation), you must specify your replacement operand as an expandable (double-quoted) string ("...")

    • However, $2 and $3 - even tough they look like PowerShell variables - are actually placeholders for what the regex operation matched, and therefore must be passed through to the .NET regex engine.

    • To that end (to prevent up-front expansion by PowerShell), they must be escaped as `$2 and `$3, using `, the so-called backtick, PowerShell's escape character.

    • Note:

      • If you use a verbatim (single-quoted) string ('...') - which is the best choice if interpolation is not needed - placeholders such as $2 and $3 can be used as-is.

      • As an alternative to the expandable string solution below, you can conceptually separate the aspect of up-front expansion and the verbatim string to pass to the .NET regex engine via -f, the format operator:

        # Same as: "Part `$2`$3 $NewObjName.txt"
        ('Part $2$3 {0}.txt' -f $NewObjName)
        

Therefore:

$_.name -replace '(\d?)(\d)(\d)', "Part `$2`$3 $NewObjName.txt"
  • Related