Windows: คัดลอก / ย้ายไฟล์ด้วยนิพจน์ปกติของชื่อไฟล์หรือไม่


10

โดยทั่วไปฉันต้องการเรียกใช้:

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

ฉันรู้ว่าxcopyไม่รองรับการค้นหาชื่อไฟล์นิพจน์ปกติ

ฉันไม่สามารถหาวิธีทราบได้ว่าPowerShellมีCmdletไฟล์ที่จะคัดลอกหรือไม่; และถ้าเป็นเช่นนั้นจะรู้ได้อย่างไรว่ามันรองรับการจับคู่ชื่อไฟล์นิพจน์ปกติหรือไม่

ทุกคนสามารถคิดวิธีการคัดลอก / ย้ายไฟล์ซ้ำด้วยการจับคู่ชื่อไฟล์ regex?


1
ควรย้ายไปที่ stackoverflow ใช่ไหม
user33788

1
@ smoknheap: อาจเป็นได้ทั้งฉันพบว่าการเขียนสคริปต์ Powershell กำลังกลายเป็นเครื่องมือของผู้ใช้ที่เพิ่มมากขึ้นเรื่อย ๆ นี่เป็นคำถามการแทนที่ xcopy มากกว่าคำถามการสคริปต์
Doltknuckle

คำตอบ:


5

ฉันชอบใช้คำสั่ง Powershell ทั้งหมดเมื่อฉันสามารถ หลังจากการทดสอบเล็กน้อยนี่เป็นสิ่งที่ดีที่สุดที่ฉันสามารถทำได้

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

สามบรรทัดแรกเป็นเพียงการทำให้อ่านง่ายขึ้นคุณสามารถกำหนดตัวแปรภายในคำสั่งจริงได้หากต้องการ กุญแจสำคัญในตัวอย่างโค้ดนี้คือคำสั่ง "Where-Object" ซึ่งเป็นตัวกรองที่ยอมรับการจับคู่นิพจน์ปกติ ควรสังเกตว่าการรองรับการแสดงออกปกติเป็นบิตแปลก ฉันพบการ์ดอ้างอิง 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]

ตอนนี้ถ้าคุณต้องการรายงานเส้นทางเพื่อให้แน่ใจว่าคุณมีทุกอย่างถูกต้อง คุณสามารถใช้คำสั่ง "เขียนโฮสต์" นี่คือรหัสที่จะให้คำแนะนำแก่คุณเกี่ยวกับสิ่งที่เกิดขึ้น

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

สิ่งนี้ควรส่งคืนสตริงที่เกี่ยวข้อง หากคุณไม่ได้อะไรเลยคุณจะรู้ว่ารายการใดมีปัญหา

หวังว่านี่จะช่วยได้


โปรดทราบว่าคุณไม่จำเป็นต้องใช้ที่$item.FullNameนั่น - คุณสมบัติที่เหมาะสมจะถูกนำมาโดยอัตโนมัติหากคุณผ่านวัตถุ FileInfo (ไม่ควรคุณเนื่องจากพลังงานของ PowerShell มาจากการผ่านวัตถุที่มีโครงสร้างไม่ใช่สตริง) นอกจากนี้คุณสามารถใส่ทุกอย่างไว้ในท่อเดียว: ((gci $source) -match $filter) | cp -dest $destination(ดัดแปลงเล็กน้อยเพื่อความกะทัดรัด - รู้สึกอิสระที่จะเปลี่ยนแปลง; ฉันแค่บอกว่าforeachไม่จำเป็นต้องมี)
Joey

เมื่อฉันทำการทดสอบฉันไม่สามารถทำให้วัตถุไปปฎิบัติได้อย่างถูกต้อง นั่นคือการบังคับให้ฉันใช้คำสั่ง foreach ฉันจะลองโค้ดของคุณและดูว่าเกิดอะไรขึ้น ขอบคุณสำหรับการชี้ให้เห็นว่า
Doltknuckle

สิ่งนี้มีปัญหาเช่นเดียวกันกับของฉันหรือไม่ที่ทำให้ไดเรกทอรีปลายทางแบนออก xcopy โดยปกติแล้วจะรักษาโครงสร้างไดเรกทอรีในไดเรกทอรีปลายทางใช่ไหม
user33788

Copy-Item : Cannot bind argument to parameter 'Path' because it is null
เอียนบอยด์

โปรดทราบTrimว่าไม่ได้มีวัตถุประสงค์เพื่อลบสตริงออกจากจุดสิ้นสุดของสตริงอื่น แต่จะลบอินสแตนซ์ทั้งหมดของอักขระในสตริงพารามิเตอร์จากจุดเริ่มต้นและจุดสิ้นสุดของสตริงที่ถูกเรียก ในกรณีของคุณถ้า$item.Nameมีตัวพิมพ์ใหญ่ C มันจะลบตัวอักษรไดรฟ์ C ออกจากจุดเริ่มต้นของสตริงด้วย
Andris

3

PowerShell เป็นเครื่องมือที่ยอดเยี่ยมสำหรับงานนั้น คุณสามารถใช้Copy-Item cmdlet สำหรับกระบวนการคัดลอก คุณสามารถไปป์กับ cmdlets อื่นสำหรับคำสั่ง copy ที่ซับซ้อนนี่คือคนที่ทำอย่างนั้น :)

นิพจน์ทั่วไปใช้คลาส. NET RegEx จากเนมสเปซ System.Text.RegularExpressions ซึ่งมีวิธีใช้อย่างรวดเร็วในคลาสเหล่านี้

PowerShell ยังมีตัวดำเนินการ -match และ -replaceที่สามารถใช้เมื่อทำการ pipelining ด้วย copy-item

นอกจากนี้ยังมีเครื่องมือที่จะช่วยคุณสร้าง RegEx เองเช่นเพื่อนของ RegEx


imho, -matchและควรจะกล่าวก่อนที่จะเข้าสู่-replace System.Text.RegularExpressions.RegExอย่างน้อยสำหรับฉันฉันไม่ค่อยได้ใช้[regex]โดยตรง แต่ฉันไม่บ่อยใช้-matchและ-replaceผู้ประกอบการ สำหรับการสร้างนิพจน์ทั่วไปฉันพบว่า PowerShell มีประโยชน์มากในการทดสอบและปรับแต่ง regex ที่คุณเขียนด้วย
Joey

ฉันขอคำตอบสำหรับคำตอบของคุณในคำถามนี้: superuser.com/questions/149808/ …
Ian Boyd

0

เป็นความคิด แต่ต้องการงานบางอย่าง

dir -r | ? {$ _ -match '[0-9] {13} \. (gif | jpg | png)'} | % {xcopy $ _. ชื่อเต็ม c: \ temp}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.