Переименовать элемент в Powershell, заменить старое имя с помощью функций

У меня есть список файлов:

PS S:\temp> dir


    Directory: S:\temp


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         3/28/2016   2:07 AM          0 00001_asdfasdfsa df.txt
-a---         3/28/2016   2:07 AM          0 00002_asdfasdfsa df - Copy (3).txt
-a---         3/28/2016   2:07 AM          0 00003_asdfasdfsa df - Copy.txt
-a---         3/28/2016   2:07 AM          0 00004_asdfasdfsa df - Copy (6).txt
-a---         3/28/2016   2:07 AM          0 00005_asdfasdfsa df - Copy (5).txt
-a---         3/28/2016   2:07 AM          0 00006_asdfasdfsa df - Copy (4).txt
-a---         3/28/2016   2:07 AM          0 00007_asdfasdfsa df - Copy (2).txt
-a---         3/28/2016   2:07 AM          0 700006_asdfasdfsa df - Copy (4) - Copy.txt


PS S:\temp>

Я хочу переименовать те, которые начинаются с пяти цифр и подчеркивания. Новое имя добавит номер, который я указал, к старшим номерам этих имен файлов. Например, если я добавлю 10, новые имена будут:

PS S:\temp> dir


    Directory: S:\temp


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         3/28/2016   2:07 AM          0 00011_asdfasdfsa df.txt
-a---         3/28/2016   2:07 AM          0 00012_asdfasdfsa df - Copy (3).txt
-a---         3/28/2016   2:07 AM          0 00013_asdfasdfsa df - Copy.txt
-a---         3/28/2016   2:07 AM          0 00014_asdfasdfsa df - Copy (6).txt
-a---         3/28/2016   2:07 AM          0 00015_asdfasdfsa df - Copy (5).txt
-a---         3/28/2016   2:07 AM          0 00016_asdfasdfsa df - Copy (4).txt
-a---         3/28/2016   2:07 AM          0 00017_asdfasdfsa df - Copy (2).txt
-a---         3/28/2016   2:07 AM          0 700006_asdfasdfsa df - Copy (4) - Copy.txt


PS S:\temp>

Теперь мой код PowerShell:

dir * | ?{$_.name -match '^\d{5}_.+'} | Rename-Item -NewName {$_.name -replace '^(\d{5})(_.+)', ((([convert]::ToInt32('$1', 10) + 12).ToString("00000")) + '$2')} -whatif

Я не могу найти никаких ошибок в моем коде. Но когда я запускаю его, я получаю следующее сообщение об ошибке:

Rename-Item : The input to the script block for parameter 'NewName' failed. Exception calling "ToInt32" with "2" argument(s): "Could not find any recognizable digits."
At line:1 char:62
+ dir * | ?{$_.name -match '^\d{5}_.+'} | Rename-Item -NewName {$_.name -replace ' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (S:\temp\00001_asdfasdfsa df.txt:PSObject) [Rename-Item], ParameterBindingException
    + FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.RenameItemCommand

У меня вопрос, где я не прав? Это потому, что я не должен использовать функции в заменяющей части replace оператор? Если так, то как написать сложную логику в -newname{}? Благодарю.

2 ответа

Решение

Вы не можете использовать -replace и массируйте данные во время замены. Ваша замена не удалась как строковый литерал $1 не может быть преобразовано в целое число. Как обсуждалось в аналогичном вопросе: передавая функцию в функцию Powershell (заменить), вы можете использовать блок сценариев и статический метод регулярного выражения.nNet. Replace,

$replaceBlock = {
    # Groups 0 contains the whole match. 1 is the first group... and so on.
    ([convert]::ToInt32($args[0].Groups[1],10) + 12).ToString("00000") + $args[0].Groups[2]
}

Get-ChildItem | Where-Object{$_.name -match '^\d{5}_.+'} | Rename-Item -NewName {
    [Regex]::Replace($_.name, '^(\d{5})(_.+)', $replaceBlock)
} -whatif

Вы можете использовать встроенный блок скрипта, но его извлечение делает код чище. Однако я бы, вероятно, использовал -match и вернулся $matches возражать делать то же самое.

Get-ChildItem | Where-Object{$_.name -match '^(\d{5})(_.+)'} | Rename-Item -NewName {
    ([int]$Matches[1] + 12).ToString("00000") + $Matches[2]
} -whatif

Обратите внимание, что я обновил where-object иметь группы захвата.

Ха-ха, я получил ответ.

dir * | ?{$_.name -match '^\d{5}_.+'} | Rename-Item -NewName {(([convert]::toint32($_.name.substring(0, 5), 10) + 12).ToString("00000")) + $_.name.substring(5)} -whatif

Просто обнаружил, что я могу использовать любой код в -newname{} блок. Но я до сих пор не понимаю, почему мой -replace путь не сработал.

Другие вопросы по тегам