Windows: Arquivo copiar / mover com expressões regulares de nome de arquivo?

10

eu basicamente quero correr:

C:\>xcopy [0-9]{13}\.(gif|jpg|png) s:\TargetFolder /s

Eu sei xcopyque não suporta pesquisas de nome de arquivo de expressão regular.

não consigo descobrir como descobrir se o PowerShell precisa Cmdletcopiar arquivos; e, se houver, como descobrir se ele suporta correspondência de nome de arquivo de expressão regular.

Alguém pode pensar em uma maneira de executar um arquivo recursivo copiar / mover com correspondência de nome de arquivo regex?

Ian Boyd
fonte
1
isso deve ser movido para stackoverflow certo?
precisa saber é o seguinte
1
@smoknheap: Podem ser os dois, acho que os scripts do Powershell estão se tornando cada vez mais uma ferramenta de Usuário Avançado. Essa é mais uma pergunta de substituição do xcopy e uma questão de script.
precisa saber é o seguinte

Respostas:

5

Eu gosto de usar todos os comandos do Powershell quando posso. Após alguns testes, é o melhor que posso fazer.

$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter} 
foreach ($item in $bin) {Copy-Item -Path $item.FullName -Destination $destination}

As três primeiras linhas são apenas para facilitar a leitura, você pode definir as variáveis ​​dentro dos comandos reais, se desejar. A chave para esse exemplo de código é o comando "Where-Object", que é um filtro que aceita correspondência de expressão regular. Note-se que o suporte a expressões regulares é um pouco estranho. Encontrei um cartão de referência em PDF aqui com os caracteres suportados no lado esquerdo.

[EDITAR]

Como "@Johannes Rössel" mencionou, você também pode reduzir as duas últimas linhas para uma única linha.

((Get-ChildItem -Path $source) -match $filter) | Copy-Item -Destination $destination

A principal diferença é que a maneira de Johannes faz a filtragem de objetos e a minha maneira faz a filtragem de texto. Ao trabalhar com o Powershell, quase sempre é melhor usar objetos.

[EDIT2]

Como o @smoknheap mencionado, os scripts acima nivelam a estrutura da pasta e colocam todos os seus arquivos em uma pasta. Não tenho certeza se existe uma opção que mantém a estrutura da pasta. Eu tentei a opção -Recurse e ela não ajuda. A única maneira de fazer isso funcionar é voltar à manipulação de strings e adicionar pastas ao meu filtro.

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

Tenho certeza de que existe uma maneira mais elegante de fazer isso, mas pelos meus testes funciona. Ele reúne tudo e filtra as correspondências de nomes e os objetos de pasta. Eu tive que usar o método ToString () para obter acesso à manipulação de string.

[EDIT3]

Agora, se você deseja relatar o caminho, verifique se tudo está correto. Você pode usar o comando "Write-Host". Aqui está o código que lhe dará algumas dicas sobre o que está acontecendo.

cls
$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Write-Host "
----
Obj: $item
Path: "$item.fullname"
Destination: "$item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

Isso deve retornar as seqüências relevantes. Se você não encontrar nada em algum lugar, saberá com qual item está tendo problemas.

Espero que isto ajude

Doltknuckle
fonte
Observe que você não precisa usá $item.FullName-lo - a propriedade apropriada será obtida automaticamente se você passar um objeto FileInfo (imho, você não deveria, pois o poder do PowerShell vem da passagem de objetos estruturados, e não de string). Além disso, você pode colocar tudo em um único pipeline: ((gci $source) -match $filter) | cp -dest $destination(ligeiramente adaptado à brevidade - sinta-se à vontade para mudar; estou apenas dizendo que isso foreaché desnecessário).
Joey
Quando eu estava testando, não conseguia fazer com que os objetos fossem canalizados corretamente. Essa é a vez que me força a usar o comando foreach. Vou tentar o seu código e ver o que acontece. Obrigado por apontar isso.
Doltknuckle
isso tem o mesmo problema que o meu, onde nivela o diretório de destino? O xcopy normalmente preservaria a estrutura de diretórios no diretório de destino, certo?
precisa saber é o seguinte
Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd
Observe que Trimnão se destina a remover uma string do final de outra string; em vez disso, remove todas as instâncias dos caracteres na string de parâmetros do início e do final da string em que é chamada. No seu caso, se $item.Namecontiver um C maiúsculo, ele também removerá a letra da unidade C do início da string.
Andris
3

O PowerShell é uma excelente ferramenta para essa tarefa. Você pode usar o cmdlet Copy-Item para o processo de cópia. Você pode canalizá-lo com outros cmdlets para comandos de cópia complexos, aqui está alguém que fez exatamente isso :)

Expressões regulares usam a classe .NET RegEx do espaço para nome System.Text.RegularExpressions, há instruções rápidas sobre essa classe

O PowerShell também possui os operadores -match e -replace que podem ser usados ​​ao canalizar com o item de cópia

Existem também ferramentas para ajudá-lo a criar o próprio RegEx, por exemplo, amigo RegEx

armannvg
fonte
Imho, -matche -replacedeve ser mencionado antes de entrar System.Text.RegularExpressions.RegEx. Pelo menos para mim, eu raramente uso [regex]diretamente; porém eu não freqüentemente usam o -matche -replaceoperadores. Quanto à criação de expressões regulares, achei o PowerShell bastante útil para testar e refinar uma regex que você está escrevendo também.
Joey
Eu pedi a resposta para a sua resposta nesta pergunta: superuser.com/questions/149808/…
Ian Boyd
0

como uma idéia, mas precisa de algum trabalho

dir -r | ? {$ _ -match '[0-9] {13} \. (gif | jpg | png)'} | % {xcopy $ _. nome completo c: \ temp}

user33788
fonte