Как рекурсивно обрезать имена файлов в PowerShell? - PullRequest
0 голосов
/ 18 июня 2020

Мне нужно усечь имена файлов до 35 символов (включая расширение), поэтому я запускаю этот скрипт, и он работает в собственном каталоге (PowerShell, Windows 10).

Get-ChildItem *.pdf | rename-item -NewName {$_.name.substring(0,31) + $_.Extension} 

Затем я хотел примените тот же сценарий, включая подкаталоги:

Get-ChildItem -Recurse -Include *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}

Этот сценарий выдал мне такую ​​ошибку для каждого файла:

Rename-Item : Error in input to script block for parameter 'NewName'. Exception when calling "Substring" with the arguments "2": "The index and length must reference a location in the string. Parameter name: length"
On line: 1 Character: 62
+ ... *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\User\prsn..._file_name_long.pdf:PSObject) [Rename-Item], ParameterBindingException
    + FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.RenameItemCommand

Я пробовал этот, но он не go на подкаталоги: Команда для усечения всех имен файлов до 255 символов

Я нашел этот, но ответа на него нет: https://superuser.com/questions/1188711/how-to-recursively-truncate-filenames-and-directory-names-in-powershell

Ответы [ 3 ]

1 голос
/ 18 июня 2020

Я не думаю, что вы можете использовать $ _ таким образом. Я думаю, вам нужно обернуть его в ForEach l oop, чтобы ссылки работали таким образом. Как только это будет сделано, вам нужно будет указать путь к файлу, который вы хотите переименовать:

Что-то вроде:

Get-ChildItem -Recurse -Include *.pdf -File | 
ForEach-Object{
    Rename-Item -Path $_.FullName -NewName ( $_.BaseName.SubString(0, 31) + $_.Extension )
    }

Обратите внимание, что я использовал круглые скобки вместо фигурных скобок. Если вы используете блок сценария, он может не оцениваться. Есть и другие способы сделать это, но я думаю, что использование скобок является наиболее очевидным.

Обратите внимание, я использовал $_.BaseName вместо name. Базовое имя не включает расширение. хотя я не знаю, как работает ваша подстрока, я оставил это на ваше усмотрение.

Вы можете объединить это с @ ответом Матиаса или его модификацией. Это может дать вам лучший или более надежный способ получить новое имя файла. Я не тестировал, но может выглядеть примерно так:

Get-ChildItem -Recurse -Include *.pdf -File | 
    ForEach-Object{        
        Rename-Item -Path $_.FullName -NewName ( ($_.Name -replace '(?<=^.{35}).*$') + $_.Extension )
        }
1 голос
/ 19 июня 2020

Правильное сообщение об ошибке:
Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.

Причина в том, что второй аргумент больше, чем длина имени файла. например, "abc".Substring(0,4) выбрасывает.

Ответ

$renameTarget = dir -File -Recurse *.pdf | ? { $_.Name.Length -gt 35 }
$renameTarget | Rename-Item -NewName {
  $_.name.substring(0, 31) + ".pdf"
}

или

dir *.pdf -File -Recurse | Rename-Item -NewName {
  $_.name.substring(0, [Math]::Min($_.BaseName.length, 31)) + ".pdf"
}
1 голос
/ 18 июня 2020

Используйте оператор регулярного выражения -replace, чтобы удалить что-либо после первых 35 символов - он просто проигнорирует любую строку, которая не содержит по крайней мере 35 символов, и вернет ее как есть:

$_.Name -replace '(?<=^.{35}).*$'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...