Remova os caracteres de colchetes em nomes de arquivos usando o Powershell

2

Eu tenho uma grande biblioteca de documentos armazenados em um servidor Sharepoint que foi migrado de um banco de dados antigo do Access, o controle de versões desses documentos era controlado pelo usuário e anexado ao final do nome do arquivo quando as alterações eram feitas.

por exemplo.

  1. Doc1-test (1.0) .doc
  2. Doc1-teste (1.1) .doc
  3. Doc2-example (2.1) .doc
  4. Doc2-example (2.2) .doc

Agora estamos usando o SharePoint para controlar o controle de versão e precisamos excluir a versão que está no nome do arquivo.

Eu tive sucesso moderado com o seguinte roteiro;

gi * | % { rni $_ ($_.Name -replace '(1.0)', '') }

mas não consigo excluir os colchetes do nome do arquivo. Então, no meu diretório de testes, os arquivos mudaram para o seguinte

Doc1-doc (1.0) .doc ----- Doc1-doc (). doc

Os números variam de 1,0 a cerca de 4,5, e há mais de 1200 documentos, por isso não me importo de ter que usar um script individual para cada número de versão.

    
por StewartM 07.04.2015 / 12:01

2 respostas

3

O problema que você está enfrentando é que -replace do PowerShell usa Expressões regulares para pesquisa.

Isso significa que os colchetes ( () ) da sua consulta de pesquisa estão sendo interpretados como um grupo de captura .

Nesse caso, você deseja referenciá-los como caracteres literais, portanto, é necessário escapar dos colchetes. No RegEx, isso é feito com uma barra invertida ( \ ).

Então, -replace '\(1.0\)','' deve fazer isso.

Como você está usando o RegEx, é possível aproveitá-lo e executá-lo de uma só vez especificando um caractere "número" classe ou "conjunto" de caracteres em vez de números de versão reais, como seu padrão de pesquisa

Então, algo como:

gi * | % { rni $_ ($_.Name -replace '\(1.[0-9]\)', '') }

Removerá (1.<any number from 0 to 9>) dos nomes dos arquivos.

Se você quiser remover os colchetes e qualquer coisa entre eles, você pode usar o "qualquer caractere ( . ) qualquer quantidade de vezes ( * )" Padrão RegEx:

ou seja: -replace '\(.*\)',''

Nota: O RegEx pode surpreendê-lo (pense em colchetes externos e internos em um único nome de arquivo, neste cenário), portanto faça backups de seus arquivos e execute os testes primeiro. :)

    
por 07.04.2015 / 15:23
2

but I cannot get it to delete the brackets from the file name. So in my testing directory the files changed to the following

Doc1-doc(1.0).doc ----- Doc1-doc().doc

Isso ocorre porque replace usa regex e parênteses ( grupo de captura ) deve ser ignorado. A maneira mais fácil de escapar de todo o texto é usar [regex] :: Escape método :

gi * | % { rni $_ ($_.Name -replace [regex]::Escape('(1.0)'), '') }

Note que apenas remover tudo entre parênteses criará conflitos para arquivos como Doc1-test(1.1).doc e Doc1-test(1.0).doc - ambos serão mapeados para Doc1-test.doc .

Aqui está minha versão com regex que corresponderá apenas aos dígitos separados por pontos entre parênteses no final do nome do arquivo sem extensão. Eu não ligo com conflitos de nome de arquivo neste código, porque não sei o resultado desejado.

# Get all objects in current directory that match wildcard: *(*.*).doc
Get-ChildItem -Path '.\' -Filter '*(*.*).doc' |
    # Skip folders, because XXX(1.1).doc is a valid folder name
    Where-Object {!$_.PSIsContainer} |
        # For each file
        ForEach-Object {
            # New file name = 
            # File Directory + (File name w\o extension with regex pattern (\(\d+\.\d+\))$ replaced with empty string) + File extension

            # Note, that it will create confilcts for files such as Doc1-test(1.1).doc and Doc1-test(1.0).doc,
            # both of them will end with name Doc1-test.doc
            $NewFileName = Join-Path -Path $_.DirectoryName -ChildPath (($_.BaseName -replace '(\(\d+\.\d+\))$', [string]::Empty) + $_.Extension)

            # Basic logging
            Write-Host "Renaming: $($_.FullName) -> $NewFileName"

            # Rename file.
            Rename-Item -Path $_.FullName -NewName $NewFileName
        }

Explicação do regex (\(\d+\.\d+\))$

1st Capturing group (\(\d+\.\d+\))

\( matches the character ( literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\. matches the character . literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\) matches the character ) literally

$ assert position at end of the string
    
por 07.04.2015 / 15:22