2016-03-27 7 views
1

Я список файлов: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> 

Я хочу renamem те, которые начинаются с пятью номерами и подчеркиванием. Новое имя добавит число, указанное в число ведущих имен файлов. Например, если добавить 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{}? Благодарю.

+1

Причина, по которой ваша замена не срабатывает, связана с тем, как работает -replace. См. Этот ответ: http://stackoverflow.com/questions/8163061/passing-a-function-to-powershells-replace-функция. В основном «$ 1» буквально означает строку «$ 1», и механизм регулярных выражений не получает от этого руки. – Matt

ответ

1

Вы не можете использовать -replace и массировать данные во время замены. Ваша замена не сработала, поскольку строковый литерал $1 не может быть преобразован в целое. Как обсуждалось в аналогичном вопросе: Passing a function to Powershell's (replace) function вы можете использовать скриптовый блок и статический метод regex .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 иметь группы захвата.

+0

Спасибо, Мэтт. –

0

Ха-ха, у меня есть ответ.

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

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