Windows: Datei kopieren / verschieben mit regulären Dateinamenausdrücken?

10

Ich möchte im Grunde laufen:

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

Ich weiß, dass xcopydie Suche nach Dateinamen mit regulären Ausdrücken nicht unterstützt wird.

ich kann nicht herausfinden, wie um herauszufinden , ob Powershell eine hat , CmdletDateien zu kopieren; und wenn ja, wie kann man herausfinden, ob es den Dateinamenabgleich mit regulären Ausdrücken unterstützt?

Kann sich jemand eine Möglichkeit vorstellen, eine rekursive Dateikopie / -verschiebung mit Regex-Dateinamen durchzuführen?

Ian Boyd
quelle
1
Dies sollte in den Stackoverflow verschoben werden, oder?
user33788
1
@smoknheap: Es könnte beides sein, ich finde, dass Powershell-Skripte immer mehr zu einem Power-User-Tool werden. Dies ist eher eine Xcopy-Ersatzfrage als eine Skriptfrage.
Doltknuckle

Antworten:

5

Ich benutze gerne alle Powershell-Befehle, wenn ich kann. Nach ein paar Tests ist dies das Beste, was ich tun kann.

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

Die ersten drei Zeilen dienen lediglich der besseren Lesbarkeit. Sie können die Variablen in den eigentlichen Befehlen definieren, wenn Sie möchten. Der Schlüssel zu diesem Codebeispiel ist der Befehl "Where-Object", ein Filter, der den Abgleich regulärer Ausdrücke akzeptiert. Es sollte beachtet werden, dass die Unterstützung regulärer Ausdrücke etwas seltsam ist. Ich habe hier eine PDF-Referenzkarte gefunden , die die unterstützten Zeichen auf der linken Seite enthält.

[BEARBEITEN]

Wie "@Johannes Rössel" erwähnt hat, können Sie auch die letzten beiden Zeilen auf eine einzige Zeile reduzieren.

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

Der Hauptunterschied besteht darin, dass Johannes Art und Weise Objekte filtert und meine Art Text filtert. Bei der Arbeit mit Powershell ist es fast immer besser, Objekte zu verwenden.

[EDIT2]

Wie in @smoknheap erwähnt, reduzieren die oben genannten Skripte die Ordnerstruktur und legen alle Ihre Dateien in einem Ordner ab. Ich bin nicht sicher, ob es einen Schalter gibt, der die Ordnerstruktur beibehält. Ich habe den -Recurse-Schalter ausprobiert und es hilft nicht. Die einzige Möglichkeit, dies zum Laufen zu bringen, besteht darin, zur Zeichenfolgenmanipulation zurückzukehren und meinem Filter Ordner hinzuzufügen.

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

Ich bin mir sicher, dass es einen eleganteren Weg gibt, dies zu tun, aber nach meinen Tests funktioniert es. Es sammelt alles und filtert dann sowohl nach Namensübereinstimmungen als auch nach Ordnerobjekten. Ich musste die ToString () -Methode verwenden, um Zugriff auf die String-Manipulation zu erhalten.

[EDIT3]

Wenn Sie nun den Pfad melden möchten, um sicherzustellen, dass alles korrekt ist. Sie können den Befehl "Write-Host" verwenden. Hier ist der Code, der Ihnen einige Hinweise gibt, was los ist.

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

Dies sollte die relevanten Zeichenfolgen zurückgeben. Wenn Sie irgendwo nichts bekommen, wissen Sie, mit welchem ​​Artikel Probleme auftreten.

Hoffe das hilft

Doltknuckle
quelle
Beachten Sie, dass Sie es dort nicht verwenden müssen $item.FullName- die entsprechende Eigenschaft wird automatisch übernommen, wenn Sie ein FileInfo-Objekt übergeben (dies sollte nicht der Fall sein, da die Leistung von PowerShell durch das Übergeben strukturierter Objekte und nicht durch Zeichenfolgen erzielt wird). Darüber hinaus können Sie alles in einer einzigen Pipeline zusammenfassen: ((gci $source) -match $filter) | cp -dest $destination(der Kürze halber leicht angepasst - Sie können sich jederzeit ändern; ich sage nur, dass dies foreachdort nicht erforderlich ist).
Joey
Als ich es getestet habe, konnte ich die Objekte nicht richtig leiten. Das zwingt mich wiederum, den Befehl foreach zu verwenden. Ich werde Ihren Code ausprobieren und sehen, was passiert. Vielen Dank für den Hinweis.
Doltknuckle
Hat dies das gleiche Problem wie meins, bei dem das Zielverzeichnis abgeflacht wird? xcopy würde normalerweise die Verzeichnisstruktur im Zielverzeichnis beibehalten, oder?
user33788
Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd
Beachten Sie, dass dies Trimnicht dazu gedacht ist, eine Zeichenfolge vom Ende einer anderen Zeichenfolge zu entfernen, sondern alle Instanzen der Zeichen in der Parameterzeichenfolge vom Anfang und Ende der Zeichenfolge, für die sie aufgerufen wird. Wenn in Ihrem Fall $item.Nameein Großbuchstabe C enthalten ist, wird auch der Laufwerksbuchstabe C vom Anfang der Zeichenfolge entfernt.
Andris
3

PowerShell ist ein hervorragendes Tool für diese Aufgabe. Sie können das Cmdlet Copy-Item für den Kopiervorgang verwenden. Sie können es mit anderen Cmdlets für komplexe Kopierbefehle weiterleiten. Hier ist jemand, der genau das getan hat :)

Reguläre Ausdrücke verwenden die .NET RegEx-Klasse aus dem System.Text.RegularExpressions-Namespace. Es gibt eine schnelle Anleitung für diese Klasse

PowerShell verfügt auch über die Operatoren -match und -replace , die beim Pipelining mit copy-item verwendet werden können

Es gibt auch Tools, mit denen Sie RegEx selbst erstellen können, z. B. RegEx Buddy

armannvg
quelle
Imho, -matchund -replacesollte vor dem Betreten erwähnt werden System.Text.RegularExpressions.RegEx. Zumindest für mich benutze ich selten [regex]direkt; aber ich Sie verwenden häufig die -matchund -replaceBetreiber. Beim Erstellen der regulären Ausdrücke fand ich PowerShell sehr nützlich, um einen regulären Ausdruck, den Sie schreiben, zu testen und zu verfeinern.
Joey
Ich habe um die Antwort auf Ihre Antwort in dieser Frage gebeten: superuser.com/questions/149808/…
Ian Boyd
0

als Idee, braucht aber etwas Arbeit

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

user33788
quelle