Windows: copia / sposta file con espressioni regolari di nome file?


10

sostanzialmente voglio correre:

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

so xcopyche non supporta ricerche di nomi di file con espressioni regolari.

non riesco a scoprire come scoprire se PowerShell deve Cmdletcopiare i file; e se lo fa, come scoprire se supporta la corrispondenza del nome file delle espressioni regolari.

Qualcuno può pensare a un modo per eseguire una copia / spostamento di un file ricorsivo con la corrispondenza del nome file regex?


1
questo dovrebbe essere spostato nello stackoverflow giusto?
user33788

1
@smoknheap: potrebbe essere entrambe le cose, trovo che lo scripting Powershell stia diventando sempre più uno strumento Power User. Questa è più una domanda di sostituzione di xcopy che una domanda di scripting.
Doltknuckle,

Risposte:


5

Mi piace usare tutti i comandi di Powershell quando posso. Dopo un po 'di test, questo è il massimo che posso fare.

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

Le prime tre righe servono solo a semplificare la lettura, è possibile definire le variabili all'interno dei comandi effettivi, se lo si desidera. La chiave di questo esempio di codice è il comando "Where-Object" che è un filtro che accetta la corrispondenza delle espressioni regolari. Va notato che il supporto per le espressioni regolari è un po 'strano. Ho trovato una scheda di riferimento PDF qui che ha i caratteri supportati sul lato sinistro.

[MODIFICARE]

Come menzionato "@Johannes Rössel", puoi anche ridurre le ultime due righe a una sola riga.

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

La differenza principale è che il modo di Johannes fa il filtro degli oggetti e il mio il filtro del testo. Quando si lavora con Powershell, è quasi sempre meglio usare oggetti.

[EDIT2]

Come menzionato @smoknheap, gli script precedenti appiattiranno la struttura delle cartelle e metteranno tutti i tuoi file in una cartella. Non sono sicuro se esiste un interruttore che mantiene la struttura delle cartelle. Ho provato l'opzione -Recurse e non aiuta. L'unico modo per farlo funzionare è tornare alla manipolazione delle stringhe e aggiungere cartelle al mio 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,"")
    }

Sono sicuro che esiste un modo più elegante per farlo, ma dai miei test funziona. Raccoglie tutto e quindi filtra sia le corrispondenze dei nomi sia gli oggetti delle cartelle. Ho dovuto usare il metodo ToString () per accedere alla manipolazione delle stringhe.

[Edit3]

Ora se vuoi segnalare il percorso per assicurarti di avere tutto corretto. È possibile utilizzare il comando "Write-Host". Ecco il codice che ti darà alcuni suggerimenti su cosa sta succedendo.

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

Questo dovrebbe restituire le stringhe pertinenti. Se non ottieni nulla da qualche parte, saprai con quale oggetto si verificano problemi.

Spero che questo ti aiuti


Si noti che non è necessario utilizzarlo $item.FullNamelì: la proprietà appropriata viene acquisita automaticamente se si passa un oggetto FileInfo (imho, non dovresti, poiché la potenza di PowerShell deriva dal passaggio di oggetti strutturati, non da stringhe). Inoltre, puoi mettere tutto in una singola pipeline: ((gci $source) -match $filter) | cp -dest $destination(leggermente adattato alla brevità - sentiti libero di cambiare; sto solo dicendo che foreachnon è necessario lì).
Joey,

Quando lo stavo testando, non riuscivo a far convogliare correttamente gli oggetti. Questo è il turno che mi costringe a usare il comando foreach. Proverò il tuo codice a vedere cosa succede. Grazie per la segnalazione.
Doltknuckle,

questo ha lo stesso problema del mio in cui si appiattisce la directory di destinazione? xcopy normalmente preserverebbe la struttura delle directory nella directory di destinazione, giusto?
user33788

Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd,

Si noti che Trimnon è destinato a rimuovere una stringa dalla fine di un'altra stringa, ma rimuove tutte le istanze dei caratteri nella stringa di parametri dall'inizio e dalla fine della stringa su cui viene chiamata. Nel tuo caso, se $item.Namecontiene una C maiuscola, rimuoverà anche la lettera di unità C dall'inizio della stringa.
Andris,

3

PowerShell è uno strumento eccellente per tale compito. È possibile utilizzare il cmdlet Copy-Item per il processo di copia. È possibile eseguire il pipeline con altri cmdlet per comandi di copia complessi, ecco qualcuno che ha fatto esattamente questo :)

Le espressioni regolari utilizzano la classe .NET RegEx dallo spazio dei nomi System.Text.RegularExpressions, in questa classe sono disponibili istruzioni rapide

PowerShell ha anche gli operatori -match e -replace che possono essere utilizzati durante il pipelining con copy-item

Ci sono anche strumenti per aiutarti a creare lo stesso RegEx, ad es. Amico RegEx


Imho, -matche -replacedovrebbe essere menzionato prima di entrare System.Text.RegularExpressions.RegEx. Almeno per me, lo uso raramente [regex]direttamente; però io faccio spesso uso la -matche -replaceoperatori. Per quanto riguarda la creazione delle espressioni regolari, ho trovato PowerShell molto utile nel testare e perfezionare una regex che stai scrivendo.
Joey,

ho chiesto la risposta alla tua risposta in questa domanda: superuser.com/questions/149808/…
Ian Boyd

0

come idea ma ha bisogno di un po 'di lavoro

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.