Как рекурсивно добавить к имени файла в powershell? - PullRequest
1 голос
/ 19 февраля 2020

У меня есть несколько файлов .txt в папках / их подпапках.

Я хочу добавить _old к их именам файлов.

Я пытался:

Get-ChildItem -Recurse | Rename-Item -NewName {$_.name -replace '.txt','_old.txt' }

Это приводит к:

  1. Некоторые файлы обновляются правильно
  2. Некоторые файлы обновляются неправильно - они получают _old дважды - пример: .._old_old.txt
  3. Есть несколько ошибки: Rename-Item : Source and destination path must be different.

Ответы [ 2 ]

3 голосов
/ 19 февраля 2020

Для предотвращения случайного переименования уже переименованных файлов повторного ввода перечисления файлов и, следовательно, его переименования многократного раза, заключает ваш Get-ChildItem вызов в () оператор группировки , который гарантирует, что весь вывод собран первый [1] , перед отправкой результатов по конвейеру:

(Get-ChildItem -Recurse) |
  Rename-Item -NewName { $_.name -replace '\.txt$', '_old.txt' }

Обратите внимание, что я использовал \.txt$ в качестве регулярного выражения [2] , чтобы гарантировать, что за литералом . (\.) следует строка txt в конце ($) имени файла сопоставляется, чтобы предотвратить ложные срабатывания (например, файл с именем Atxt.csv или даже каталог с именем * 1032) * случайно совпадет с вашим исходным регулярным выражением).

Примечание. Необходимость сначала собрать все выходные данные Get-ChildItem возникает из-за фундаментальной работы конвейера PowerShell: объекты (по умолчанию) отправляются в конвейер one на один и обрабатывается принимающей командой по мере их eived . Это означает, что без (...) вокруг Get-ChildItem, Rename-Item начинает переименовывать файлы до того, как Get-ChildItem завершит перечисление файлов, что вызывает проблемы. См. этот ответ для получения дополнительной информации о том, как работает конвейер PowerShell.
Подсказка к Мэтью для предложения включения этой информации.

Однако я предлагаю оптимизировать вашу команду следующим образом:

(Get-ChildItem -Recurse -File -Filter *.txt) | 
  Rename-Item -NewName { $_.BaseName + '_old' + $_.Extension }
  • -File ограничивает вывод в файлы (также не возвращает каталогов ).

  • -Filter - это самый быстрый способ ограничить результаты заданным шаблоном подстановки.

  • $_.BaseName + '_old' + $_.Extension использует простую конкатенацию строк через подкомпоненты имени файла.

    • Альтернативой является использование -replace:
      $_.Name -replace '\.[^.]+$', '_old$&'

Примечание что если вы хотите выполнить это несколько раз и хотите исключить файлы, переименованные в предыдущем запуске, добавьте -Exclude *_old.txt к вызову Get-ChildItem.


[1] из-за изменения в как Get-ChildItem реализован в PowerShell [Core] 6 + (теперь он внутренне сортирует результаты, что неизменно требует сбора Прежде всего, (...) корпус больше не является строго необходимым , но это можно рассматривать как деталь реализации, поэтому для концептуальной ясности лучше продолжать использовать (...).

[2] Оператор PowerShell -replace работает с регулярными выражениями (регулярные выражения); он не выполняет подстроку literal , которая ищет метод .Replace() типа [string].

0 голосов
/ 19 февраля 2020

Следующая команда вернет ВСЕ файлы из текущей папки и подпапок в текущем каталоге, из которого выполняется команда.

Get-ChildItem -Recurse

Из-за этого вы также переворачиваете все файлы, которые уже обновлены и теперь имеют суффикс _old.

Вам нужно использовать параметры -Include -Exclude командлета Get-Childitem, чтобы игнорировать файлы, которые уже имеют суффикс _old, и соответствовать вашему включению критерии, например.

Get-ChildItem -Recure -Include "*.txt" -Exclude "*_old"

Затем перенаправьте результаты в команду переименования элемента

Описание командлета Get-ChildItem можно найти здесь.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...