Windows: Salin / pindahkan file dengan nama file ekspresi reguler?

10

pada dasarnya saya ingin menjalankan:

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

saya tahu xcopytidak mendukung pencarian nama file ekspresi reguler.

saya tidak dapat menemukan cara untuk mengetahui apakah PowerShell memiliki Cmdletuntuk menyalin file; dan jika ya, bagaimana cara mengetahui apakah itu mendukung pencocokan nama file ekspresi reguler.

Adakah yang bisa memikirkan cara untuk melakukan copy / pindah file rekursif dengan pencocokan nama file regex?

Ian Boyd
sumber
1
ini harus dipindahkan ke stackoverflow kan?
user33788
1
@smoknheap: Bisa jadi keduanya, saya menemukan bahwa scripting Powershell menjadi semakin banyak alat Power User. Ini lebih merupakan pertanyaan penggantian xcopy daripada pertanyaan scripting.
Doltknuckle

Jawaban:

5

Saya suka menggunakan semua perintah Powershell ketika saya bisa. Setelah sedikit pengujian, ini yang terbaik yang bisa saya lakukan.

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

Tiga baris pertama hanya untuk membuatnya lebih mudah dibaca, Anda dapat mendefinisikan variabel di dalam perintah yang sebenarnya jika Anda mau. Kunci untuk sampel kode ini adalah perintah "Di mana-Objek" yang merupakan filter yang menerima pencocokan ekspresi reguler. Perlu dicatat bahwa dukungan ekspresi reguler agak aneh. Saya menemukan kartu referensi PDF di sini yang memiliki karakter yang didukung di sisi kiri.

[EDIT]

Seperti "@Johannes Rössel" sebutkan, Anda juga dapat mengurangi dua baris terakhir menjadi satu baris.

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

Perbedaan utamanya adalah cara Johannes melakukan penyaringan objek dan cara saya melakukan penyaringan teks. Saat bekerja dengan Powershell, hampir selalu lebih baik menggunakan objek.

[EDIT2]

Seperti @smoknheap disebutkan, skrip di atas akan meratakan struktur folder dan meletakkan semua file Anda dalam satu folder. Saya tidak yakin apakah ada saklar yang mempertahankan struktur folder. Saya mencoba saklar -Recurse dan itu tidak membantu. Satu-satunya cara agar ini berfungsi adalah kembali ke manipulasi string dan menambahkan folder ke filter saya.

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

Saya yakin ada cara yang lebih elegan untuk melakukan ini, tetapi dari tes saya berhasil. Itu mengumpulkan semuanya dan kemudian memfilter untuk pencocokan nama dan objek folder. Saya harus menggunakan metode ToString () untuk mendapatkan akses ke manipulasi string.

[EDIT3]

Sekarang jika Anda ingin melaporkan jalur untuk memastikan semuanya sudah benar. Anda dapat menggunakan perintah "Write-Host". Berikut kode yang akan memberi Anda beberapa petunjuk tentang apa yang terjadi.

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

Ini harus mengembalikan string yang relevan. Jika Anda tidak mendapatkan apa pun di suatu tempat, Anda akan tahu barang apa yang bermasalah.

Semoga ini membantu

Doltknuckle
sumber
Perhatikan bahwa Anda tidak perlu menggunakannya di $item.FullNamesana - properti yang sesuai diambil secara otomatis jika Anda melewatkan objek FileInfo (sebaiknya, karena kekuatan PowerShell berasal dari melewati objek terstruktur, bukan string). Selain itu, Anda dapat memasukkan semuanya ke dalam satu saluran pipa: ((gci $source) -match $filter) | cp -dest $destination(sedikit disesuaikan untuk singkatnya - jangan ragu untuk mengubah; Saya hanya mengatakan bahwa foreachtidak perlu di sana).
Joey
Ketika saya mengujinya, saya tidak bisa mendapatkan benda untuk pipa dengan benar. Itulah giliran memaksa saya untuk menggunakan perintah foreach. Saya akan mencoba kode Anda dan melihat apa yang terjadi. Terima kasih telah menunjukkannya.
Doltknuckle
apakah ini memiliki masalah yang sama dengan saya di mana ia meratakan direktori tujuan? xcopy biasanya akan mempertahankan struktur direktori pada direktori tujuan, kan?
user33788
Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd
Harap dicatat bahwa Trimini tidak dimaksudkan untuk menghapus string dari ujung string lain, melainkan menghapus semua instance karakter dalam string parameter dari awal dan akhir string yang dipanggil. Dalam kasus Anda jika $item.Nameberisi huruf kapital C, huruf kapital C juga akan dihapus dari awal string.
Andris
3

PowerShell adalah alat yang luar biasa untuk tugas itu. Anda dapat menggunakan cmdlet Salin-Item untuk proses penyalinan. Anda dapat menyalurkannya dengan cmdlet lain untuk perintah penyalinan yang kompleks, berikut adalah seseorang yang melakukan hal itu :)

Ekspresi reguler menggunakan kelas .NET RegEx dari namespace System.Text.RegularExpressions, ada cara cepat di kelas ini

PowerShell juga memiliki operator -match and -replace yang dapat digunakan saat pipelining dengan copy-item

Ada juga alat untuk membantu Anda membuat RegEx itu sendiri, misalnya teman RegEx

armannvg
sumber
Imho, -matchdan -replaceharus disebutkan sebelum masuk System.Text.RegularExpressions.RegEx. Setidaknya bagi saya, saya jarang menggunakan [regex]secara langsung; namun saya tidak sering menggunakan -matchdan -replaceoperator. Sedangkan untuk membuat ekspresi reguler saya menemukan PowerShell sangat berguna dalam menguji dan menyempurnakan regex yang Anda tulis juga.
Joey
Saya telah meminta jawaban untuk jawaban Anda dalam pertanyaan ini: superuser.com/questions/149808/…
Ian Boyd
0

sebagai ide tetapi perlu kerja

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

pengguna33788
sumber