จะลบไดเรกทอรีทั้งหมดซ้ำด้วย PowerShell 2.0 ได้อย่างไร


308

วิธีที่ง่ายที่สุดในการลบไดเรกทอรีและไดเรกทอรีย่อยทั้งหมดใน PowerShell คืออะไร ฉันใช้ PowerShell V2 ใน Windows 7

ฉันได้เรียนรู้จากหลายแหล่งว่าคำสั่งที่ชัดเจนที่สุดRemove-Item $targetDir -Recurse -Forceทำงานไม่ถูกต้อง ซึ่งรวมถึงคำชี้แจงในวิธีใช้แบบออนไลน์ของ PowerShell V2 (พบโดยใช้Get-Help Remove-Item -Examples) ที่ระบุว่า:

... เนื่องจากพารามิเตอร์ Recurse ใน cmdlet นี้มีข้อผิดพลาดคำสั่งใช้ Get-Childitem cmdlet เพื่อรับไฟล์ที่ต้องการและจะใช้ตัวดำเนินการไปป์ไลน์เพื่อส่งไปยัง cmdlet ลบรายการ ...

ฉันได้เห็นตัวอย่างต่าง ๆ ที่ใช้Get-ChildItemและไพพ์ไปที่Remove-Itemแต่ตัวอย่างมักจะลบไฟล์บางชุดตามตัวกรองไม่ใช่ไดเรกทอรีทั้งหมด

ฉันกำลังมองหาวิธีที่สะอาดที่สุดในการระเบิดทั้งไดเรกทอรีไฟล์และไดเรกทอรีลูกโดยไม่ต้องสร้างข้อความเตือนผู้ใช้โดยใช้รหัสจำนวนน้อยที่สุด ซับหนึ่งจะดีถ้าง่ายต่อการเข้าใจ


2
PowerShell ฉันรู้ แต่RD /S /Q
รูเบนส์ Farias

เป็นไปได้ที่ซ้ำกัน: stackoverflow.com/questions/1667145/…
Rubens Farias

ฉันไม่คิดว่ามันจะซ้ำกัน ฉันตรวจสอบ 1667145 ก่อนโพสต์ มีการถามว่าเหตุใด PowerShell จึงไม่ตั้งค่าพารามิเตอร์ Recurse bool อย่างเหมาะสมเมื่อเรียกใช้วิธีการนำรายการออกของผู้ให้บริการ PowerShell ที่กำหนดเอง ฉันถูกถามเกี่ยวกับพฤติกรรมการลบรายการเนื่องจากเกี่ยวข้องกับผู้ให้บริการระบบไฟล์ในตัว
Matt Spradley

2
"RD / S / Q" ดูเหมือนจะไม่ทำงานใน PowerShell - พูดว่า "Remove-Item: ไม่พบพารามิเตอร์ตำแหน่งที่ยอมรับอาร์กิวเมนต์ '/ q'
BrainSlugs83

5
rdเป็นนามแฝงสำหรับRemove-Itemใน powershell cmd /c "rd /s /q"ทำงานได้แม้ว่า
codekaizen

คำตอบ:


510
Remove-Item -Recurse -Force some_dir

ทำงานได้จริงตามที่โฆษณาไว้ที่นี่

rm -r -fo some_dir

เป็นนามแฝงชวเลขที่ใช้งานได้เช่นกัน

เท่าที่ฉันเข้าใจ-Recurseพารามิเตอร์จะไม่ทำงานอย่างถูกต้องเมื่อคุณลองลบชุดไฟล์ที่กรองซ้ำแล้วซ้ำอีก สำหรับการฆ่าคนเดียวและทุกอย่างด้านล่างดูเหมือนว่าจะทำงานได้ดี


5
ฉันคิดว่าคุณถูกต้อง ฉันได้รับ "ไม่สามารถลบรายการที่ 'บางไดเรกทอรี' เพราะใช้งานอยู่" เกิดข้อผิดพลาดและสันนิษฐานว่าเป็นปัญหากับอัลกอริทึมการเรียกซ้ำและไปค้นหาวิธีแก้ปัญหา ปรากฎว่าฉันมีกระบวนการที่ฉันใช้ก่อนหน้านี้ในสคริปต์ที่ทำงานในไดเรกทอรีเป้าหมาย เมื่อเปลี่ยนสคริปต์เพื่อรอกระบวนการอื่นคำสั่ง "ลบรายการ - กู้คืน - บังคับใช้" จะทำงาน ดูเสมอในกระจกครั้งแรก :)
แมตต์ Spradley

15
ฉันพบว่าฉันต้องเรียกใช้สองครั้งเมื่อเรียกใช้ในไดเรกทอรีที่มีไดเรกทอรีย่อย ในครั้งแรกจะมีข้อผิดพลาด "ไดเรกทอรีไม่ว่าง" จำนวนมาก ครั้งที่สองมันเสร็จสมบูรณ์โดยไม่มีข้อผิดพลาด
Kristopher Johnson

5
Kristopher Johnson ฉันได้รับข้อผิดพลาดที่คล้ายกันกับเครื่องมือที่แตกต่างกันใน Windows 7 ดูเหมือนว่าการลบโทรจะส่งกลับก่อนหน้าไฟล์หรือโฟลเดอร์ที่ถูกลบจริงทำให้เกิดปัญหาบางครั้ง ดูเหมือนว่าจะเกิดขึ้นใน Explorer, Far, cmd และ PowerShell
Joey

2
@ โจอี้ "ดูเหมือนว่าการโทรลบจะส่งกลับก่อนหน้าไฟล์หรือโฟลเดอร์ที่ถูกลบจริง ๆ ทำให้เกิดปัญหาบางครั้ง" -> เพื่อความกระจ่าง: โฟลเดอร์หลักจะไม่ถูกลบและมีข้อผิดพลาดต่อไปนี้: "[โฟลเดอร์หลัก] ไม่สามารถลบได้เพราะไม่ว่างเปล่า" ฉันเห็นสิ่งนี้เกิดขึ้นตลอดเวลาบนไดรฟ์เครือข่าย (ช้า) ทางออกเดียวคือวิธีเก่า: cmd /c rdตามที่ระบุไว้ด้านล่าง
Davor Josipovic

6
เกิดข้อผิดพลาด "ไดเรกทอรีไม่ว่างเปล่า" คืออะไร serverfault.com/questions/199921/powershell-remove-forceอาจจะดีกว่าที่จะรับเด็ก * - รวม * .csv -recurse | ลบรายการที่ฉันไม่รู้ ดูstackoverflow.com/a/1668471/206730
Kiquenet

39

ฉันใช้:

rm -r folderToDelete

มันใช้งานได้สำหรับฉันเหมือนจับใจ (ฉันขโมยมาจาก Ubuntu)


ไม่จำเป็นต้องใช้ cygwin, git หรือเครื่องมืออื่น ๆ ที่สามารถจำลอง bash shell บน Windows ได้หรือไม่?
Pete

19
@ Pet, ไม่, มันไม่ต้องการอะไรนอกจาก PowerShell rmเป็นชื่อแทนRemove-Itemในการกำหนดค่าเริ่มต้นของ PowerShell ตรวจสอบผลลัพธ์ของGet-Alias rmรายละเอียดเพิ่มเติม นี่-rคือการใช้ประโยชน์จากพฤติกรรมการจับคู่บางส่วนของ PowerShell กับพารามิเตอร์ เนื่องจากRemove-Itemมีเพียงหนึ่งพารามิเตอร์ที่ขึ้นต้นด้วย 'r' เท่านั้น-Recurseดังนั้นจึงควร-rจับคู่ rm -rดังนั้นต่อไปนี้ทุกคนจะทำงานเดียวกัน: rm -re, Remove-Item -Recurse, (หมายเหตุว่าไม่ว่าrm -rfมิได้rm -r -fจะทำงาน แต่rm -r -fo. จะ-rfตรงกับค่าพารามิเตอร์และไม่มี-fการแข่งขันมากกว่าหนึ่ง.)
chwarr

1
วิธีการเกี่ยวกับที่ นามแฝง Powershell rm สำหรับ "ลบรายการ - ถอนเงิน - บังคับ some_dir" ทำงานได้ดีกว่าโดยตรงโดยใช้รายการลบ ฉันได้รับข้อผิดพลาดเดียวกัน "ไม่สามารถลบรายการที่ 'บางไดเรกทอรี' ฉันเปลี่ยนจากการลบรายการเป็น rm -r โดยไม่มีข้อผิดพลาด!?
Greg

น่าสนใจ ฉันมีเครื่องมือ cygwin ในกล่องของฉันและได้ลองrm -rf folderและแน่นอนว่ามันล้มเหลว ตอนแรกฉันลงคะแนนให้คำตอบ (เพราะมันบอกว่า Ubuntu) ขอบคุณที่คอมเม้นท์โดย @chwarr ฉันลองมันโดยไม่ใช้fมันเลยเลือก alias แทนชื่อ rm binary ฉันหวังว่า Tuan จะอัปเดตแหล่งที่มาของเขา (ไม่แน่ใจว่า Tuan รู้ว่ามันเป็นนามแฝงหรือคิดว่ามันเป็นยูนิกซ์ rm ;-)
Joshua Ball

2
อาจเป็นเพราะฉันใช้-Rแทน-r(แต่เท่าที่ฉันรู้ PowerShell เป็นเหมือนส่วนที่เหลือของ Windows ไม่คำนึงถึงขนาดตัวพิมพ์ดังนั้นจึงไม่ควรสร้างความแตกต่าง) แต่ฉันมีข้อผิดพลาดที่โฟลเดอร์ที่ฉันพยายามจะลบคือ ไม่ว่างเปล่า
rbaleksandar

25

เมื่อทำการลบไฟล์ซ้ำ ๆ โดยใช้วิธีการแบบธรรมดาRemove-Item "folder" -Recurseบางครั้งฉันเห็นข้อผิดพลาดเป็นระยะ ๆ :[folder] cannot be removed because it is not empty.

คำตอบนี้พยายามป้องกันข้อผิดพลาดนั้นโดยการลบไฟล์ทีละรายการ

function Get-Tree($Path,$Include='*') { 
    @(Get-Item $Path -Include $Include -Force) + 
        (Get-ChildItem $Path -Recurse -Include $Include -Force) | 
        sort pspath -Descending -unique
} 

function Remove-Tree($Path,$Include='*') { 
    Get-Tree $Path $Include | Remove-Item -force -recurse
} 

Remove-Tree some_dir

รายละเอียดที่สำคัญคือการเรียงลำดับของรายการทั้งหมดด้วยpspath -Descendingเพื่อให้ใบถูกลบต่อหน้าราก การเรียงลำดับถูกดำเนินการกับpspathพารามิเตอร์เนื่องจากมีโอกาสทำงานกับผู้ให้บริการอื่นนอกเหนือจากระบบไฟล์ -Includeพารามิเตอร์เป็นเพียงความสะดวกสบายถ้าคุณต้องการกรองรายการที่จะลบ

มันแบ่งออกเป็นสองฟังก์ชั่นเนื่องจากฉันพบว่ามีประโยชน์ที่จะเห็นสิ่งที่ฉันกำลังจะลบโดยการเรียกใช้

Get-Tree some_dir | select fullname

1
ในขณะที่การแก้ไขปัญหาโดยใช้ PowerShell ในสคริปต์สร้าง TFS นี่พิสูจน์แล้วว่าเป็นคำตอบที่ถูกต้อง
rcabr

นี่คือทางออกสำหรับฉันเช่นกัน มีบางจุดที่คนดีของฉัน!
Jammer

ทำงานให้ฉัน ฉันไม่สามารถลบเนื้อหาในโฟลเดอร์แบบเรียกซ้ำ แต่โซลูชันของคุณใช้งานได้สำหรับฉัน ขอบคุณ
SheldonH

นี่เป็นโซลูชันที่แข็งแกร่งมาก
Max Young

ฉันไม่แน่ใจว่าทำไมคำตอบที่ยอมรับมีการโหวตมากมาย - ฉันเองยังคงได้รับข้อผิดพลาดเป็นระยะ ๆ ที่ใช้remove-item -recurseใน Powershell v5 ดังนั้นโซลูชันนี้ดีที่สุดสำหรับฉัน
JonoB


11

ลองตัวอย่างนี้ หากไม่มีไดเร็กทอรีอยู่จะไม่มีข้อผิดพลาดเกิดขึ้น คุณอาจต้องใช้ PowerShell v3.0

remove-item -path "c:\Test Temp\Test Folder" -Force -Recurse -ErrorAction SilentlyContinue

7

ใช้คำสั่ง DOS ของโรงเรียนเก่า:

rd /s <dir>

หากนี่เป็นส่วนหนึ่งของสคริปต์คุณจะต้องใช้/q(โหมด Quiet อย่าถามว่าตกลงเพื่อลบแผนผังไดเรกทอรีด้วย / S) หรือไม่
wildeyes

6

ด้วยเหตุผลบางอย่างคำตอบของ John Rees บางครั้งก็ไม่ได้ผลในกรณีของฉัน แต่มันทำให้ฉันไปในทิศทางต่อไปนี้ ก่อนอื่นฉันพยายามลบไดเรกทอรีซ้ำด้วยตัวเลือก buggy -recurse หลังจากนั้นฉันลงมาในทุกส่วนย่อยที่เหลือและลบไฟล์ทั้งหมด

function Remove-Tree($Path)
{ 
    Remove-Item $Path -force -Recurse -ErrorAction silentlycontinue

    if (Test-Path "$Path\" -ErrorAction silentlycontinue)
    {
        $folders = Get-ChildItem -Path $Path –Directory -Force
        ForEach ($folder in $folders)
        {
            Remove-Tree $folder.FullName
        }

        $files = Get-ChildItem -Path $Path -File -Force

        ForEach ($file in $files)
        {
            Remove-Item $file.FullName -force
        }

        if (Test-Path "$Path\" -ErrorAction silentlycontinue)
        {
            Remove-Item $Path -force
        }
    }
}

คุณสามารถทำซ้ำข้อผิดพลาดเมื่อเรียกใช้ฟังก์ชั่นของฉันได้อย่างไร ฉันอยากรู้ว่าฉันสามารถปรับปรุงได้
John Rees

ขออภัยจำการตั้งค่าที่แน่นอน : / ฉันคิดว่ามันเป็นเมื่อหลายไดเรกทอรีย่อยที่เกี่ยวข้อง มันเกิดขึ้นว่าการเรียก "ลบรายการ - บังคับ - ชดเชย" ไม่ได้ลบไฟล์ทั้งหมดและในกรณีนั้นการลบทรีครั้งสุดท้ายล้มเหลวเนื่องจากไดเรกทอรีไม่ว่างเปล่า นั่นเป็นสาเหตุที่ฉันมากับโซลูชันใหม่เพื่อลองรุ่น buggy ในตัว (-force) ก่อนจากนั้นจึงลงไปในแต่ละไดเรกทอรีด้วยตนเองและลบ "ด้วยตนเอง" ที่เหลืออยู่ รุ่นนี้มีการใช้งานอย่างสม่ำเสมอและจนถึงตอนนี้ก็ยังใช้งานได้ สาเหตุเดียวที่ทำให้มันล้มเหลวคือเมื่อโปรแกรมยังคงจัดการกับไดเรกทอรี
jdoose

5

เพื่อหลีกเลี่ยงข้อผิดพลาด "ไดเรกทอรีไม่ว่าง" ของคำตอบที่ยอมรับเพียงใช้คำสั่ง DOS เก่าที่ดีตามที่แนะนำก่อน ไวยากรณ์ PS เต็มพร้อมสำหรับการคัดลอกวางคือ:

& cmd.exe /c rd /S /Q $folderToDelete

3
มันยังคงให้ข้อผิดพลาด "ไดเรกทอรีไม่ว่าง" สำหรับโฟลเดอร์!
Oncel Umut TURER

2

ฉันใช้วิธีอื่นที่ได้รับแรงบันดาลใจจาก @ john-rees ด้านบน - โดยเฉพาะอย่างยิ่งเมื่อวิธีการของเขาเริ่มที่จะล้มเหลวสำหรับฉันในบางจุด โดยทั่วไปจะรีรีทรีย่อยและเรียงลำดับไฟล์ตามพา ธ ความยาว - ลบจากยาวที่สุดไปยังสั้นที่สุด

Get-ChildItem $tfsLocalPath -Recurse |  #Find all children
    Select-Object FullName,@{Name='PathLength';Expression={($_.FullName.Length)}} |  #Calculate the length of their path
    Sort-Object PathLength -Descending | #sort by path length descending
    %{ Get-Item -LiteralPath $_.FullName } | 
    Remove-Item -Force

เกี่ยวกับเวทมนตร์ -LiteralPath นี่คือ gotchya อีกอันที่อาจกระทบคุณ: https://superuser.com/q/212808


2
del <dir> -Recurse -Force # I prefer this, short & sweet

หรือ

remove-item <dir> -Recurse -Force

หากคุณมีไดเรกทอรีขนาดใหญ่สิ่งที่ฉันมักจะทำคือ

while (dir | where name -match <dir>) {write-host deleting; sleep -s 3}

รันสิ่งนี้บนเทอร์มินัลพาวเวอร์เชลอื่นและมันจะหยุดเมื่อมันเสร็จ


ฉันยอมรับความคิดของคุณกับการตรวจสอบจะมีประโยชน์ แต่แทบจะไม่แตกต่างจากการพิมพ์ข้อความเมื่อเสร็จแล้วและในกรณีที่มีปัญหาในการหยุดการลบรายการห่วงของคุณจะไม่สิ้นสุด
Raúl Salinas-Monteagudo

@ RaúlSalinas-Monteagudo จริง แต่มันก็แน่นอนสำหรับสถานการณ์กรณีการใช้งานแยงหรือไม่ตั้งใจ มันจะต้องมีขนาดเล็กพอสำหรับคนที่จะจำและพิมพ์ได้ทุกที่และไม่ต้องเรียกใช้ไฟล์. ps1 ที่มีความซับซ้อนเป็นเพียงไดเรกทอรี
Gajendra D Ambi

2

บางครั้งการลบทรีของโฟลเดอร์ทั้งหมดจะใช้งานได้และบางครั้งก็ล้มเหลวด้วยข้อผิดพลาด "Directory not empty" จากนั้นความพยายามที่จะตรวจสอบว่าโฟลเดอร์ยังคงอยู่อาจส่งผลให้เกิดข้อผิดพลาด "การเข้าถึงถูกปฏิเสธ" หรือ "การเข้าถึงที่ไม่ได้รับอนุญาต" ผมไม่ทราบว่าทำไมถึงเกิดขึ้นแม้ว่าความเข้าใจบางคนอาจจะได้รับจากนี้การโพสต์ StackOverflow

ฉันสามารถแก้ไขปัญหาเหล่านี้ได้โดยระบุลำดับที่รายการภายในโฟลเดอร์ถูกลบและเพิ่มความล่าช้า ต่อไปนี้ทำงานได้ดีสำหรับฉัน:

# First remove any files in the folder tree
Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Where-Object { -not ($_.psiscontainer) } | Remove-Item Force

# Then remove any sub-folders (deepest ones first).    The -Recurse switch may be needed despite the deepest items being deleted first.
ForEach ($Subfolder in Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Select-Object FullName, @{Name="Depth";Expression={($_.FullName -split "\\").Count}} | Sort-Object -Property @{Expression="Depth";Descending=$true}) { Remove-Item -LiteralPath $Subfolder.FullName -Recurse -Force }

# Then remove the folder itself.  The -Recurse switch is sometimes needed despite the previous statements.
Remove-Item -LiteralPath $FolderToDelete -Recurse -Force

# Finally, give Windows some time to finish deleting the folder (try not to hurl)
Start-Sleep -Seconds 4

บทความ Microsoft TechNet การใช้คุณสมบัติที่คำนวณได้ใน PowerShell มีประโยชน์กับฉันในการรับรายการโฟลเดอร์ย่อยเรียงตามความลึก

ปัญหาความน่าเชื่อถือที่คล้ายกันกับRD / S / Qสามารถแก้ไขได้โดยการรันDEL / F / S / Qก่อนRD / S / Qและใช้RDเป็นครั้งที่สองหากจำเป็น - โดยมีการหยุดในระหว่าง (เช่นการใช้pingตามที่แสดง ด้านล่าง)

DEL /F /S /Q "C:\Some\Folder\to\Delete\*.*" > nul
RD /S /Q "C:\Some\Folder\to\Delete" > nul
if exist "C:\Some\Folder\to\Delete"  ping -4 -n 4 127.0.0.1 > nul
if exist "C:\Some\Folder\to\Delete"  RD /S /Q "C:\Some\Folder\to\Delete" > nul


1

เคล็ดลับที่มีประโยชน์อื่น:

หากคุณพบไฟล์จำนวนมากที่มีแบบแผนชื่อเหมือนหรือคล้ายกัน (เช่นไฟล์ mac ที่มีชื่อนำหน้าจุด ... การดึงไฟล์ที่มีชื่อเสียง) คุณสามารถลบออกได้อย่างง่ายดายด้วยบรรทัดเดียวจาก PowerShell ดังนี้:

ls -r .* | rm

บรรทัดนี้จะลบไฟล์ทั้งหมดที่มีจุดในจุดเริ่มต้นของชื่อในไดเรกทอรีปัจจุบันและไฟล์ทั้งหมดที่มีสถานการณ์เดียวกันภายในโฟลเดอร์อื่น ๆ ภายในไดเรกทอรีนี้ด้วย โปรดระวังเมื่อใช้งาน : D


ทำไมไม่ใช้rm -rf .*? ฉันไม่มีอำนาจในการทดสอบ แต่ฉันคิดว่ามันจะได้ผล
Vini.g.fer

1
มันเป็นเรื่องง่าย; หากคุณเพิ่งลบ "| rm" ออกจากคำสั่งคุณสามารถดูภาพพาโนรามาทั้งหมดของสิ่งที่คุณกำลังจะลบหลังจากที่คุณแน่ใจแล้วคุณสามารถทำคำสั่งให้เสร็จสมบูรณ์
Daniel Alberto Lepe Ayala

โดยรอบ, สำหรับผู้ที่ต้องการความช่วยเหลือทางการเงิน, (สำหรับผู้ที่ต้องการสั่งซื้อ) จากผู้ขายไปยังผู้ขาย, ส่งคำถามให้กับคุณ: ls -r -h. * | rm
Daniel Alberto Lepe Ayala

1

ในการลบเนื้อหาทั้งหมดรวมถึงการใช้โครงสร้างโฟลเดอร์

get-childitem $dest -recurse | foreach ($_) {remove-item $_.fullname -recurse}

-recurseเพิ่มลงไปremove-itemเพื่อให้แน่ใจแจ้งโต้ตอบถูกปิดใช้งาน


-1
$users = get-childitem \\ServerName\c$\users\ | select -ExpandProperty name

foreach ($user in $users)

{
remove-item -path "\\Servername\c$\Users\$user\AppData\Local\Microsoft\Office365\PowerShell\*" -Force -Recurse
Write-Warning "$user Cleaned"
}

เขียนข้างต้นเพื่อทำความสะอาด logfiles โดยไม่ต้องลบไดเรกทอรีหลักและมันทำงานได้อย่างสมบูรณ์!


-2
rm -r <folder_name>
c:\>rm -r "my photos"

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