Move-Item не работает в цикле - PullRequest
6 голосов
/ 16 марта 2011
ls *.gif | Foreach { $newname = $_.Name -replace '\[','' -replace '\]',''
                     write-host $_.Name $newname
                     move-Item -Path $_.Name -Destination $newname; }
ls *.gif

Поэтому, пытаясь помочь кому-то переименовать файлы с помощью [], я обнаружил, что move-item не работает в цикле. Кажется, что он отлично работает вне цикла.

Идеи? * * 1004

Ответы [ 4 ]

7 голосов
/ 16 марта 2011

Обновление: основываясь на комментариях ниже, я хочу уточнить это: специальные символы в именах файлов требуют использования параметра -LiteralPath.-Path не может обрабатывать эти символы.За пределами цикла -Path работает, поскольку вы экранируете специальные символы с помощью `.Это невозможно при просмотре коллекции.

В цикле вместо параметра -Path необходимо использовать параметр -LiteralPath.

-LiteralPath <string[]>
    Specifies the path to the current location of the items. Unlike Path, the value of
    LiteralPath is used exactly as it is typed. **No characters are interpreted as 
    wildcards. If the path includes escape characters, enclose it in single quotation 
    marks.** Single quotation marks tell Windows PowerShell not to interpret any 
    characters as escape sequences.

SO, это будет:*

GCI -Recurse *.txt | % { Move-Item -LiteralPath $_.FullName -Destination "SomenewName" }
3 голосов
/ 20 марта 2011

Если вы используете функцию привязки конвейера PowerShell, вы можете сделать это намного проще и устранить необходимость в явном Foreach-Object напр .::1002*

ls *.gif | Move-Item -Destination {$_ -replace '\[|\]',''} -WhatIf

Это работает, потому что для параметра LiteralPath установлено значение bind ByPropertyName. Однако вы можете спросить, откуда оно получает свойство с именем «LiteralPath» на выходе Get-ChildItem (псевдоним ls). Ну, он не находит это имя свойства, однако параметр LiteralPath имеет определенный псевдоним PSPath, который существует на каждом объекте, выводимом Get-ChildItem. Вот как он связывается с параметром LiteralPath. Другой совет по скорости заключается в том, что поскольку параметр Destination также привязан к конвейеру (ByPropertyName), вы можете использовать scriptblock для предоставления значения. И внутри этого скриптового блока у вас есть доступ к объекту конвейера.

Внутри скриптового блока используется оператор -replace для создания нового имени на основе исходного полного имени. Хотя я мог бы использовать $_.FullName или даже $_.Name в этом случае (при условии, что вы хотите по существу переименовать файлы в том же каталоге), я использую просто $_. Поскольку -replace является строковым оператором, он будет приводить $_ к строке перед ее использованием. Вы можете увидеть, что это будет, выполнив:

ls *.gif | Foreach {"$_"}

Какой полный путь в этом случае, но вы должны быть осторожны, потому что вы не всегда получаете полный путь, например ::1010 *

ls | Foreach {"$_"}

отображает только имя файла. В ваших примерах (переименуйте в один и тот же каталог) это не имеет значения, но в других случаях это имеет значение. Вероятно, хорошей практикой будет просто быть явным и использовать $_.Name или $_.FullName в скрипте, но при взломе этого материала на консоли я обычно использую $_. Поговорка: это острая палка, не высовывайте глаза применимо здесь. : -)

0 голосов
/ 27 марта 2016

Это сработало для меня (по крайней мере, в моей ситуации.

Move-Item -literalpath $_.FullName -Destination ( ( ( (Join-Path -Path (Get-Location) -ChildPath $_.BaseName) -replace "\[","`[") -replace "\]","`]") ) 

Сотни фильмов и связанных с ними субтитров хранятся без папок. Решил поместить каждый фильм и субтитры в свои папки

Полный код

Get-ChildItem -File | % 
{
    if(Test-Path -LiteralPath ( Join-Path -Path (Get-Location) -ChildPath $_.BaseName ))
    {
         Move-Item -literalpath $_.FullName -Destination ( ( ( (Join-Path -Path (Get-Location) -ChildPath $_.BaseName) -replace "\[","`[") -replace "\]","`]") ) 
    }
    else
    {
        New-Item ( Join-Path -Path (Get-Location) -ChildPath $_.BaseName ) -ItemType Directory 
        Move-Item $_ -Destination ( Join-Path -Path (Get-Location) -ChildPath $_.BaseName )
    }

}
0 голосов
/ 19 марта 2011

Вы можете найти "официальную" информацию о роли "[" в строках путей в этой статье Microsoft .

Или поищите в google: Совет недели по Windows PowerShell: «В буквальном смысле слова (например, пути к файлам)».

Единственный совет, который мне не был ясен, это то, что Rename-Item не поддерживает LiteralPath, и что мы можем использовать Move-Item для переименования файлов или каталогов.

JP

...