Powershell Bug em copy / move / rename quando o nome do arquivo contém [caracteres de colchetes]?

7

Por favor, perdoe uma pergunta noob, mas fiquei completamente perplexo com essa.

Eu tenho um diretório "depositante" onde os arquivos enviados pelo usuário chegam e não tenho controle sobre os nomes dos arquivos recebidos.

Eu criei um analisador no PS que move com bastante sucesso arquivos (com base no conteúdo do nome do arquivo) para um destino apropriado.

Isso funciona bem EXCETO quando um nome de arquivo contém "[" ou "]".

Aqui está o pré-processador de "renomear", que falha na hora de renomear um arquivo que contém um dos caracteres de parênteses irritantes:

 cd $folderpath
 foreach ($i in get-childitem $folderpath) {   
     if ($i.mode.substring(0,1) -ne “d”) {
        $name = $i.name.replace("[","_")
        $name = $name.replace("]","_")
        Write-Host $i -foregroundcolor “blue”       
        Write-Host $name -foregroundcolor “green”  

        Rename-Item $i $name 

     }
 }

Isso também falha para ren, copy, move e seus equivalentes de cmdlet

Qualquer informação que você possa fornecer seria muito bem-vinda.

Obrigado antecipadamente. . .

    
por TTrewitt 19.11.2010 / 18:09

3 respostas

7

A menos que você use -LiteralPath , os colchetes causam problemas reais com o escape de caracteres. O problema é que o PowerShell descarta as strings várias vezes internamente e usa caracteres especiais para correspondência de padrões. Obter o PowerShell para reconhecer corretamente um colchete literal em uma string de caminho é complexo.

Se você estiver usando strings de aspas simples, um suporte precisa de dois backticks para escapar. Se você usa strings de aspas duplas, um suporte precisa de quatro backticks para escapar.

Se você está procurando um arquivo chamado MyFile[1].txt , você precisa usar:

'MyFile''[1''].txt'

ou:

"MyFile''''[1''''].txt"

Sim, é uma dor. Para ver por que isso acontece, você precisa saber o que está acontecendo. É fácil fazer isso trabalhando de trás para frente.

Digamos que você queira obter um arquivo chamado literalmente [ab].txt .

O padrão de curinga correspondente a Get-ChildItem significa que, se obtiver [ab].txt como o caminho, ele procurará arquivos com os nomes a.txt e b.txt . Então, se quisermos combinar um literal [ab].txt , temos que escapar de nossos colchetes com o caractere de escape: o backtick. Isso nos dá isso como a string real de caracteres que queremos que Get-ChildItem use para o filespec:

'[ab'].txt

No entanto, temos que passar este filespec como uma string. Isso significa que Get-ChildItem vai escapar desses backticks, mas não é isso que queremos! Nós queremos backticks literais. Então, escapamos dos backticks com backticks em nossa string para garantir que Get-ChildItem use o filespec correto:

'''[ab''].txt'

Se quisermos usar strings com aspas duplas, então temos que escapar de cada backtick novamente , pois a string de aspas duplas irá remover a string. E é assim que você acaba com isso:

"''''[ab''''].txt"

É por isso que muitas funções do PowerShell que usam filespecs têm a opção -LiteralPath .

    
por 08.04.2011 / 14:57
4

RenameItem não tem -LiteralPath para algum motivo estúpido . *

Move-Item -LiteralPath $i -destination $name

* Desculpas de um co-designer da linguagem.

    
por 19.11.2010 / 22:20
1

Isso finalmente alcançou o resultado desejado:

foreach ($i in get-childitem $folderpath) {
  if ($i.mode.substring(0,1) -ne “d”) {
    $name = $i.name.replace("[","_")
    $name = $name.replace("]","_")

   Write-Host $name -foregroundcolor “green”    
   [System.IO.File]::Move($folderPath+"\"+$i, $folderPath+"\"+$name) 
  }
}
    
por 20.11.2010 / 17:21