Windows: ¿Copiar / mover archivo con expresiones regulares de nombre de archivo?

10

Básicamente quiero correr:

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

xcopyque no admite búsquedas de nombre de archivo de expresión regular.

no puedo averiguar cómo averiguar si PowerShell tiene Cmdletque copiar archivos; y si es así, cómo averiguar si es compatible con la coincidencia de nombre de archivo de expresión regular.

¿Alguien puede pensar en una forma de realizar una copia / movimiento recursivo de archivos con coincidencia de nombre de archivo regex?

Ian Boyd
fuente
1
esto debería moverse a stackoverflow ¿verdad?
user33788
1
@smoknheap: Podría ser a la vez, creo que las secuencias de comandos de Powershell se están convirtiendo cada vez más en una herramienta para usuarios avanzados. Esta es más una pregunta de reemplazo de xcopy que una pregunta de secuencias de comandos.
Doltknuckle

Respuestas:

5

Me gusta usar todos los comandos de Powershell cuando puedo. Después de un poco de prueba, esto es lo mejor que puedo hacer.

$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}

Las primeras tres líneas son solo para que sea más fácil de leer, puede definir las variables dentro de los comandos reales si lo desea. La clave de este ejemplo de código es el comando "Where-Object", que es un filtro que acepta la coincidencia de expresiones regulares. Cabe señalar que el soporte de expresiones regulares es un poco extraño. Encontré una tarjeta de referencia en PDF aquí que tiene los caracteres admitidos en el lado izquierdo.

[EDITAR]

Como mencionó "@Johannes Rössel", también puede reducir las dos últimas líneas a una sola.

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

La principal diferencia es que la manera de Johannes hace el filtrado de objetos y mi forma de hacer el filtrado de texto. Cuando se trabaja con Powershell, casi siempre es mejor usar objetos.

[EDIT2]

Como @smoknheap mencionó, los scripts anteriores aplanarán la estructura de carpetas y colocarán todos sus archivos en una carpeta. No estoy seguro de si hay un interruptor que conserve la estructura de la carpeta. Intenté el interruptor -Recurse y no ayuda. La única forma de hacer que esto funcione es volver a la manipulación de cadenas y agregar carpetas a mi 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,"")
    }

Estoy seguro de que hay una forma más elegante de hacer esto, pero desde mis pruebas funciona. Reúne todo y luego filtra tanto las coincidencias de nombres como los objetos de carpeta. Tuve que usar el método ToString () para obtener acceso a la manipulación de cadenas.

[EDITAR3]

Ahora, si desea informar la ruta para asegurarse de tener todo correcto. Puede usar el comando "Write-Host". Aquí está el código que le dará algunas pistas sobre lo que está sucediendo.

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

Esto debería devolver las cadenas relevantes. Si no obtiene nada en alguna parte, sabrá con qué artículo está teniendo problemas.

Espero que esto ayude

Doltknuckle
fuente
Tenga en cuenta que no necesita usar $item.FullNameallí: la propiedad apropiada se toma automáticamente si pasa un objeto FileInfo (en mi opinión, no debería, ya que el poder de PowerShell proviene de pasar objetos estructurados, no cadenas). Además, puede poner todo en una sola tubería: ((gci $source) -match $filter) | cp -dest $destination(ligeramente adaptado para brevedad, no dude en cambiar; solo digo que no foreaches necesario allí).
Joey
Cuando lo estaba probando, no pude hacer que los objetos se canalizaran correctamente. Ese turno me obliga a usar el comando foreach. Voy a probar tu código y ver qué pasa. Gracias por señalar eso.
Doltknuckle
¿Tiene este el mismo problema que el mío, donde aplana el directorio de destino? xcopy normalmente preservaría la estructura del directorio en el directorio de destino, ¿verdad?
user33788
Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd
Tenga en cuenta que Trimno está destinado a eliminar una cadena del final de otra cadena, sino que elimina todas las instancias de los caracteres en la cadena de parámetros desde el principio y el final de la cadena en la que se invoca. En su caso, si $item.Namecontiene una C mayúscula, también eliminará la letra de unidad C desde el comienzo de la cadena.
Andris
3

PowerShell es una excelente herramienta para esa tarea. Puede usar el cmdlet Copy-Item para el proceso de copia. Puede canalizarlo con otros cmdlets para comandos de copia complejos, aquí hay alguien que hizo exactamente eso :)

Las expresiones regulares usan la clase .NET RegEx del espacio de nombres System.Text.RegularExpressions, hay instrucciones rápidas sobre estas clases

PowerShell también tiene los operadores -match y -replace que se pueden usar al canalizar con copy-item

También hay herramientas para ayudarlo a crear el propio RegEx, por ejemplo, amigo de RegEx

armannvg
fuente
Imho, -matchy -replacedebería mencionarse antes de entrar System.Text.RegularExpressions.RegEx. Al menos para mí, rara vez lo uso [regex]directamente; sin embargo , uso con frecuencia los operadores -matchy -replace. En cuanto a la creación de expresiones regulares, descubrí que PowerShell también es bastante útil para probar y refinar una expresión regular que está escribiendo.
Joey
He pedido la respuesta a su respuesta en esta pregunta: superuser.com/questions/149808/…
Ian Boyd
0

como una idea pero necesita algo de trabajo

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

usuario33788
fuente