PowerShell: переименуйте несколько папок, используя $_.FullName.Replace
У меня есть папка на диске Google, которая иногда не синхронизируется. Google (или кто-то другой) добавит (1) к имени каталога / файла. Затем он удалит исходный каталог, и у меня будет куча папок и файлов с именем "xxx (1)".
Я пытался написать сценарий powershell, который будет сканировать дерево каталогов и переименовывать папки / файлы, просто удаляя часть (1). Я понимаю, что это может привести к некоторым столкновениям, но я надеялся заменить большинство из них с помощью сценария. Меня не беспокоит структура каталогов, я буду восстанавливать при необходимости, но это просто неприятность.
Я пробовал несколько сценариев PowerShell, и ближе всего я дошел до этого...
Это вернет правильные новые имена папок
Get-ChildItem -Path "* (1)" -Recurse | select { $_.FullName.Replace(" (1)", "")}
Я попробовал это...
Get-ChildItem -Path "* (1)" -Recurse | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
Я получаю сообщение об ошибке "Вы не можете вызвать метод для выражения с нулевым значением".
You cannot call a method on a null-valued expression.
At line:1 char:1
+ Get-ChildItem -Path "* (1)" -Recurse | rename-item $_.FullName $_.Fu ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
2 ответа
Попробуйте заключить последнюю половину в foreach-объект, используя Rename-Item вместо Replace-Item и т. Д. И т. Д.
Get-ChildItem -Path "* (1)" -Recurse | ForEach-Object {Rename-Item -Path $_.Fullname -NewName $($_.Name.Replace(" (1)", "")) -WhatIf}
$_
это только переменная внутри блока скриптов. С:
.. | select { $_.FullName.Replace(" (1)", "")}
Вы можете get-help select-object
и увидеть первый позиционный параметр -Property
так что это сокращение от
.. | Select-Object -Property { $_.FullName.Replace(" (1)", "") }
И теперь вы можете видеть, что скрипт-блок получает файлы через конвейер, обращается к ним как $_
и вычисляет новое свойство для вывода, а $_
используется один раз для каждого файла. Когда вы пытаетесь использовать ту же технику во второй строке:
.. | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
$_
просто свободно плавающий, вы не можете использовать его таким образом, вне {}
сценарий это ничего не значит. И вы передаете входные файлы через конвейер, а также пытаетесь указать их с помощью -Path, который удваивается - конфликтующий и избыточный. И вы используете Replace вместо Rename.
Так что в другом ответе nferrell использует ForEach для создания блока скриптов. И направляет файлы в ForEach, а затем указывает их имя -Path of Rename-Item.
Что работает, но это многословно и окольным. Зачем извлекать имена файлов из конвейера и использовать ForEach, чтобы перетасовать их на другой конец командлета, только чтобы вернуть их обратно?
Get-ChildItem .. | Rename-Item -NewName { $_.Name.Replace(" (1)", "") }
Файлы поступают по конвейеру, вычисляется NewName. Нет цикла, нет удвоения ввода, нет