Как переместить первые 7 символов имени файла в конец с помощью Powershell
У моей компании миллионы старых отчетов в формате PDF. Они обычно называются в формате: 2018-09-18 - ReportName.pdf
Организация, в которую мы должны их отправить, теперь требует, чтобы мы назвали файлы в следующем формате: Report Name - 2018-09.pdf
Мне нужно переместить первые 7 символов имени файла до конца. Я думаю, что, вероятно, есть простой код для выполнения этой задачи, но я не могу понять это. Может кто-нибудь мне помочь.
Спасибо!
4 ответа
Предостережение:
Как указывает jazzdelightsme, желаемая операция переименования может привести к конфликтам имен, учитывая, что вы jazzdelightsme компонент дня из ваших дат; например,
2018-09-18 - ReportName.pdf
а также2018-09-19 - ReportName.pdf
приведет к тому же имени файла,Report Name - 2018-09.pdf
,В любом случае, я предполагаю, что операция переименования выполняется для копий исходных файлов. Кроме того, вы можете создавать копии с новыми именами в другом месте с помощью
Copy-Item
перечисляя оригиналы, но преимуществоRename-Item
является то, что он сообщит об ошибке в случае конфликта имен.
Get-ChildItem -Filter *.pdf | Rename-Item -NewName {
$_.Name -replace '^(\d{4}-\d{2})-\d{2} - (.*?)\.pdf$', '$2 - $1.pdf'
} -WhatIf
-WhatIf
предварительный просмотр операции переименования; удалите его, чтобы выполнить фактическое переименование.
добавлять -Recurse
к Get-CildItem
вызов для обработки целого поддерева каталога.
Использование -Filter
необязательно, но ускоряет обработку.
Блок скрипта (
{ ... }
) передаетсяRename-Item
"s-NewName
параметр, который включает динамическое переименование каждого входного файла ($_
) полученные отGet-ChildItem
используя выражение преобразования строки (замены).-replace
оператор использует регулярное выражение (регулярное выражение) в качестве первого операнда для выполнения замены строк на основе шаблонов; здесь регулярное выражение разбивается следующим образом:^(\d{4}-\d{2})
соответствует что-то вроде2018-09
в начале (^
) имени и - в силу того, что(...)
- захваты, которые совпадают в так называемой группе захвата, на которую можно ссылаться в строке замены по ее индексу, а именно$1
, потому что это первая группа захвата.(.*?)
захватывает остальную часть имени файла, исключая расширение в группе захвата$2
,-
?
после.*
делает подвыражение нежадным, что означает, что оно также даст возможность сопоставить последующие подвыражения, в отличие от попытки сопоставить как можно больше символов (это поведение по умолчанию, называемое жадным).
-
\.pdf$
соответствует расширению имени файла (.pdf
) в конце ($
) - обратите внимание, что дело не имеет значения..
сбежал как\.
потому что это должно быть подобрано буквально здесь (без побега,.
соответствует любому отдельному символу в одной строке).$2 - $1.pdf
является строкой замены, которая упорядочивает записи групп захвата в желаемой форме.
Обратите внимание, что любой файл, имя которого не соответствует регулярному выражению, спокойно остается один, потому что -replace
оператор пропускает входную строку, если совпадений нет, и Rename-Item
ничего не делает, если новое имя совпадает со старым.
Что-то вроде этого -
Get-ChildItem -path $path | Rename-Item -NewName {$_.BaseName.Split(' - ')[-1] + ' - ' + $_.BaseName.SubString(0,7) + $_.Extension} -WhatIf
Пояснение -
Split
выделит имя файла в зависимости от параметра-
а также[-1]
говорит PowerShell выбрать последнее из сегрегированных значений.SubString(0,7)
выберет 7 символов, начиная с первого символаBaseName
файла.- Удалить
-WhatIf
применить переименование.
Это должно работать (добавлены некоторые тестовые данные):
$test = '2018-09-18 - ReportName.pdf','2018-09-18 - Other name.pdf','other pattern.pdf','2018-09-18 - double.extension.pdf'
$test | % {
$match = [Regex]::Match($_, '(?<Date>\d{4}-\d\d)-\d\d - (?<Name>.+)\.pdf')
if ($match.Success) {
"$($match.Groups['Name'].Value) - $($match.Groups['Date'].Value).pdf"
} else {
$_
}
}
Get-ChildItem
с некоторыми RegEx и Rename-Item
может сделать это:
Get-ChildItem -Path "C:\temp" | foreach {
$newName = $_.Name -replace '(^.{7}).*?-\s(.*?)\.(.*$)','$2 - $1.$3'
$_ | Rename-Item -NewName $newName
}
RegEx
'(^.{7}).*?-\s(.*?)\.(.*$)'
/ $2 - $1.$3
(^.{7})
соответствует первым 7 символам.*?-\s
соответствует любым символам до (и включая) первого найденного-
(космическая тире)(.*?)\.
соответствует чему угодно до первой найденной точки ( .)(.*$)
соответствует расширению файла в этом случае$2 - $1.$3
складывает все вместе в измененном порядке
Это не будет правильно работать, если есть имена файлов с несколькими точками ( .).