Windows: Копирование / перемещение файла с регулярными выражениями имени файла?

18876
Ian Boyd

я в основном хочу бежать:

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

я знаю xcopy, не поддерживает регулярные выражения поиска файлов.

я не могу узнать, как узнать, если PowerShell имеет Cmdletдля копирования файлов; и если это так, как выяснить, поддерживает ли оно сопоставление имени файла с регулярным выражением.

Может кто-нибудь придумать, как выполнить рекурсивное копирование / перемещение файла с помощью сопоставления имен регулярных выражений?

10
это должно быть перемещено в stackoverflow правильно? user33788 14 лет назад 1
@smoknheap: Это может быть и то и другое, я считаю, что сценарии Powershell становятся все более и более мощным инструментом для пользователей. Это скорее вопрос замены xcopy, чем вопрос сценариев. Doltknuckle 14 лет назад 1

3 ответа на вопрос

4
Doltknuckle

Мне нравится использовать все команды Powershell, когда я могу. После небольшого тестирования это лучшее, что я могу сделать.

$source = "C:\test"  $destination = "C:\test2"  $filter = [regex] "^[0-9]\.(jpg|gif)"  $bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter}  foreach ($item in $bin)  

Первые три строки просто для облегчения чтения, вы можете определить переменные внутри фактических команд, если хотите. Ключом к этому примеру кода является команда «Где-объект», которая является фильтром, который принимает сопоставление с регулярным выражением. Следует отметить, что поддержка регулярных выражений немного странная. Я нашел ссылку PDF карту здесь, которая имеет поддерживаемые символы на левой стороне.

[РЕДАКТИРОВАТЬ]

Как уже упоминалось "@Johannes Rössel", вы также можете уменьшить последние две строки до одной строки.

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

Основное отличие состоит в том, что метод Йоханнеса выполняет фильтрацию объектов, а мой - фильтрацию текста. При работе с Powershell почти всегда лучше использовать объекты.

[EDIT2]

Как упоминалось в @smoknheap, приведенные выше сценарии сгладят структуру папок и поместят все ваши файлы в одну папку. Я не уверен, есть ли переключатель, который сохраняет структуру папок. Я попробовал переключатель -Recurse, и это не помогает. Единственный способ заставить это работать - вернуться к манипуляции со строками и добавить папки в мой фильтр.

$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,"") } 

Я уверен, что есть более элегантный способ сделать это, но из моих тестов это работает. Он собирает все и затем фильтрует как совпадения имен, так и объекты папок. Мне пришлось использовать метод ToString (), чтобы получить доступ к манипуляции со строками.

[EDIT3]

Теперь, если вы хотите сообщить путь, убедитесь, что у вас все правильно. Вы можете использовать команду «Write-Host». Вот код, который даст вам несколько советов о том, что происходит.

cls $source = "C:\test"  $destination = "C:\test2"  $filter = [regex] "^[0-9]\.(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,"") } 

Это должно вернуть соответствующие строки. Если вы где-нибудь ничего не получите, вы будете знать, с какими предметами возникают проблемы.

Надеюсь это поможет

Обратите внимание, что вам не нужно использовать `$ item.FullName` там - соответствующее свойство берется автоматически, если вы передаете объект FileInfo (imho, вы не должны этого делать, поскольку мощь PowerShell заключается в передаче структурированных объектов, а не строк). Кроме того, вы можете поместить все в один конвейер: `((gci $ source) -match $ filter) | cp -dest $ destination` (слегка адаптировано для краткости - не стесняйтесь менять; я просто говорю, что здесь нет необходимости в foreach). Joey 14 лет назад 0
Когда я тестировал его, я не мог правильно передать объекты. Это заставляет меня использовать команду foreach. Я попробую ваш код и посмотрю, что произойдет. Спасибо что подметил это. Doltknuckle 14 лет назад 0
это имеет ту же проблему, что и у меня, где он сглаживает каталог назначения? xcopy обычно сохраняет структуру каталогов в целевом каталоге, верно? user33788 14 лет назад 0
`Copy-Item: невозможно связать аргумент с параметром 'Path', потому что он имеет значение null` Ian Boyd 14 лет назад 0
Обратите внимание, что `Trim` не предназначен для удаления строки из конца другой строки, вместо этого он удаляет все вхождения символов в строке параметра из начала и конца строки, для которой она вызывается. В вашем случае, если `$ item.Name` содержит заглавную букву C, он также удалит букву диска C из начала строки. Andris 12 лет назад 0
@ Андрис, Хороший вопрос. Вы должны удалить имя файла из места назначения, чтобы заставить Copy-Item работать должным образом. Вы можете использовать другую команду замены, чтобы вытащить имя файла. Это должно работать немного лучше. Doltknuckle 12 лет назад 0
2
armannvg

PowerShell - отличный инструмент для решения этой задачи. Вы можете использовать командлет Copy-Item для процесса копирования. Вы можете передать его с помощью других командлетов для сложных команд копирования, вот кто-то, кто сделал именно это :)

Регулярные выражения используют класс .NET RegEx из пространства имен System.Text.RegularExpressions, в этом классе есть быстрые инструкции

PowerShell также имеет операторы -match и -replace, которые можно использовать при конвейерной передаче с copy-item

Есть также инструменты, которые помогут вам создать самого RegEx, например, приятель RegEx

Imho, `-match` и` -replace` должны быть упомянуты перед входом в `System.Text.RegularExpressions.RegEx`. По крайней мере, я редко использую `[regex]` напрямую; однако я * часто * использую операторы `-match` и` -replace`. Что касается создания регулярных выражений, я обнаружил, что PowerShell весьма полезен при тестировании и уточнении регулярного выражения, которое вы пишете. Joey 14 лет назад 0
я попросил ответ на ваш ответ на этот вопрос: http://superuser.com/questions/149808/powershell-file-copy-move-with-filename-regular-expressions Ian Boyd 14 лет назад 0
0
user33788

как идея, но нуждается в некоторой работе

dir -r | ? {$ _ -match '[0-9] \. (gif | jpg | png)'} | %