Как переместить первые 7 символов имени файла в конец с помощью Powershell

У моей компании миллионы старых отчетов в формате pdf. Обычно они называются в формате: 2018-09-18 - ReportName.pdf.

Организация, в которую мы должны их отправить, теперь требует, чтобы мы называли файлы в следующем формате: Report Name - 2018-09.pdf.

Мне нужно переместить первые 7 символов имени файла в конец. Я думаю, что, вероятно, есть простой код для выполнения этой задачи, но я не могу его понять. Может кто-нибудь мне помочь.

Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
2 016
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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 собирает все вместе в измененном порядке

Это не будет работать должным образом, если в нем есть имена файлов с несколькими точками (.).

Это должно работать (добавлены некоторые тестовые данные):

$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 {
        $_
    }
}

Прекрасно, но вы можете сделать это более идиоматическим для PowerShell: % { if ($_ -match '(?<Date>\d{4}-\d\d)-\d\d - (?<Name>.+)\.pdf') { "$($Matches.Name) - $($Matches.Date).pdf" } else { $_ } } или, что еще более кратко, с -replace: % { $_ -replace '(?<Date>\d{4}-\d\d)-\d\d - (?<Name>.+)\.pdf', '${Name} - ${Date}.pdf' }

mklement0 19.09.2018 18:59

Что-то вроде этого -

Get-ChildItem -path $path | Rename-Item -NewName {$_.BaseName.Split(' - ')[-1] + ' - ' + $_.BaseName.SubString(0,7) + $_.Extension} -WhatIf

Объяснение -

  1. Split будет разделять имя файла на основе параметра -, а [-1] указывает PowerShell выбрать последнее из разделенных значений.
  2. SubString(0,7) выберет 7 символов, начиная с первого символа BaseName файла.
  3. Удалите -WhatIf, чтобы применить переименование.

Обязательно проверяйте наличие коллизий, чтобы избежать потери данных (например, два отчета, один от 02.09.2018 и один от 28.09.2018 будут переименованы в один и тот же файл). Рассмотрите возможность записи файлов в новое место вместо переименования (перезаписи) старых файлов.

jazzdelightsme 19.09.2018 15:33

Даже если он перейдет в новое место, все равно будут конфликты в именах, поскольку OP хочет, чтобы к имени отчета добавлялась только часть YYYY-MM. Так что новой локации, наверное, тоже не хватит. Следовательно, предусмотрена опция -WhatIf.

Vivek Kumar Singh 19.09.2018 15:38

Да, но вы не [потенциально безвозвратно] потеряете данные таким образом, и сможете легко проверить, были ли у вас конфликты, например, проверив количество файлов в обоих местах.

jazzdelightsme 19.09.2018 15:41

Это близко, но устраняет почти все имя файла. Например, он меняет что-то с названием «2018-09-17 Report Name» на «Name - 2018-09». Мне нужно сохранить полное имя отчета.

David Maughn 19.09.2018 16:43
Ответ принят как подходящий

Предостережение:

  • Как указывает джаз, желаемая операция переименования может привести к коллизии имен, учитывая, что вы удаляете компонент дня из своих дат; например, 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

-WhatIfpreviews the renaming operation; remove it to perform actual renaming.
Add -Recurse to the Get-CildItem call to process an entire directory subtree.
The use of -Filter is optional, but it speeds up processing.

  • блок скрипта ({ ... }) передается в параметр Rename-Item-NewName, который позволяет динамически переименовывать каждый входной файл ($_), полученный от Get-ChildItem, с использованием выражения преобразования (замены) строки.

  • Оператор -replace использует регулярное выражение (регулярное выражение) в качестве своего первого операнда для выполнения замены строк на основе шаблонов; здесь регулярное выражение разбивается следующим образом:

    • ^(\d{4}-\d{2}) соответствует чему-то вроде 2018-09 в начале (^) имени и - в силу того, что он заключен в (...) - записывает это совпадение в так называемый группа захвата, на который можно ссылаться в строке замены по его индексу, а именно $1, потому что это группа захвата первый.

    • (.*?) захватывает остальную часть имени файла без учета как расширение в группе захвата $2.

      • ? после .* создает подвыражение не жадный, что означает, что он даст последующим подвыражениям возможность совпадения, а не пытаться сопоставить как можно больше символов (что является поведением по умолчанию, называемым жадный).
    • \.pdf$ соответствует расширению имени файла (.pdf) в конце ($) - обратите внимание, что регистр не имеет значения. . экранирован как \., потому что он предназначен для сопоставления здесь буквально (без экранирования . соответствует одиночному символу любой в однострочной строке).

    • $2 - $1.pdf - это строка замены, которая упорядочивает то, что захвачено группами захвата, в желаемой форме.

Обратите внимание, что любой файл, имя которого не соответствует регулярному выражению, незаметно оставляется в покое, потому что оператор -replace передает строку ввода, если совпадения нет, а Rename-Item ничего не делает, если новое имя совпадает со старым.

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