ลบไฟล์ / ไดเรกทอรีทั้งหมดยกเว้นไฟล์เดียว


244

ฉันมีไดเรกทอรีที่มีไฟล์จำนวนมาก ฉันต้องการลบไฟล์ทั้งหมดยกเว้น file.txt ฉันจะทำสิ่งนี้ได้อย่างไร

มีไฟล์จำนวนมากเกินกว่าที่จะลบไฟล์ที่ไม่ต้องการทีละรายการและชื่อของพวกเขามีความหลากหลายเกินกว่าที่จะใช้ * เพื่อลบไฟล์ทั้งหมดยกเว้นไฟล์เดียว

มีคนแนะนำให้ใช้

rm !(file.txt)

แต่มันไม่ทำงาน มันกลับมา:

Badly placed ()'s 

ระบบปฏิบัติการของฉันคือ Scientific Linux 6

ความคิดใด ๆ


13
ย้ายคนที่คุณต้องการเก็บไว้แล้วย้ายคนอื่นหรือไม่
Olivier Dulac

5
@OlivierDulac เราเป็นเพียงคนสองคนในคำถามนี้ที่ไม่คิดมากหรือไม่
Shadur

1
@shadur: ดีฉันสามารถเกี่ยวข้องกับพวกเขา: oneliners เป็นที่น่าสนใจ ... ^^
Olivier Dulac

1
ขอบคุณและใช่ฉันกำลังมองหาวิธีแก้ปัญหาหนึ่งบรรทัด มันใช้เวลานานเกินไปในการเคลื่อนย้ายไฟล์ไปเรื่อย ๆ เนื่องจากฉันต้องทำสิ่งนี้บ่อยครั้ง
Kantura

คำตอบ:


288

POSIXly:

find . ! -name 'file.txt' -type f -exec rm -f {} +

จะลบไฟล์ทั้งหมดปกติ (ซ้ำรวมทั้งคนที่ซ่อนอยู่) file.txtยกเว้น ในการลบไดเรกทอรีเปลี่ยน-type fไป-type dและเพิ่มตัวเลือกในการ-rrm

ในbashการใช้งานrm -- !(file.txt)คุณต้องเปิดใช้งาน extglob :

$ shopt -s extglob 
$ rm -- !(file.txt)

(หรือโทรbash -O extglob)

โปรดทราบว่าextglobใช้งานได้เฉพาะในbashตระกูล Korn เชลล์เท่านั้น และการใช้งานrm -- !(file.txt)อาจทำให้เกิดArgument list too longข้อผิดพลาด

ในzshคุณสามารถใช้^เพื่อปฏิเสธรูปแบบที่เปิดใช้งานExtendedglob :

$ setopt extendedglob
$ rm -- ^file.txt

หรือใช้ไวยากรณ์เดียวกันกับkshและbashกับตัวเลือกksh_globและno_bare_glob_qualเปิดใช้งาน


9
การระบุไดเรกทอรีเป็นแนวปฏิบัติที่ดี (เต็มเส้นทางในกรณีนี้หรืออาจเพิ่มคำเตือนที่นี่ที่คำสั่งนี้จะลบทุกไฟล์ที่เริ่มต้นจากไดเรกทอรีการทำงานปัจจุบันหรือไม่) ฉันก็มักจะเขียนตัวอย่างใด ๆ กับrmเป็นecho rmแทนและขอให้คนที่จะใช้เวลาเพียงออกก้องเมื่อพวกเขาเป็นจริงแน่ใจว่ามันจะทำในสิ่งที่พวกเขาต้องการ นอกจากนั้น +1 สำหรับคำตอบอย่างละเอียด
Olivier Dulac

11
ฉันขอแนะนำให้-deleteแทน-execสั้นกว่าและจดจำได้ง่ายกว่า
Izkata

6
@Izkata: -deleteไม่ได้กำหนดโดย POSIX
cuonglm

5
จะยกเว้นรายการไฟล์ได้อย่างไร
Meysam

5
@Meysam - ดูคำตอบของฉันสำหรับวิธีแก้ปัญหาที่จะจัดการกับรายการไฟล์ อื่นด้วยfindวิธีแก้ปัญหาของ Gnouc ที่คุณสามารถทำได้! \( -name one_file -o -name two_file \)เป็นต้น
mikeserv

112

อีกคนหนึ่งไปในทิศทางที่แตกต่าง (ถ้าไม่มีที่ว่างในชื่อไฟล์)

ls | grep -v file.txt | xargs rm

หรือ (ทำงานแม้ว่าจะมีช่องว่างในชื่อไฟล์)

ls | grep -v file.txt | parallel rm

จากman grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)

2
มันจะไม่ทำงานถ้าชื่อไฟล์ที่มีพื้นที่ ...
มัตเตโอ

1
Ciao @Matteo ก็ทำงานสำหรับไฟล์ที่มีช่องว่างมากเกินไป แต่คุณต้องล้อมรอบ grep ls | grep -v "a file with spaces.bin" | xargs rmรูปแบบโดยคำพูดเช่น นี่เป็นgrepไวยากรณ์ปกติ
เซบาสเตียน

1
@Sebastian ปัญหาคือไม่ได้แต่grep จะได้รับรายชื่อของข้อโต้แย้งคั่นพื้นที่ ลอง: คุณจะได้รับและrmrmtouch 'a b'; touch 'c d'; ls | grep -v 'a b' | xargs rmrm: c: No such file or directoryrm: d: No such file or directory
Matteo

1
ใช่นี่เป็นปัญหาที่พบบ่อย ดูตัวเลือก-print0ในfindและใน-0 xargsนี่เป็นวิธีแก้ปัญหา แต่ไม่สะดวกเล็กน้อย find . -maxdepth 1 -type f | grep -v 'a b' | tr '\n' '\0' | xargs -0 rm. โดยวิธีการที่ gnu parallelจัดการหลุมนี้ (ฉันเกือบจะใช้มันแทน xargs:ls | grep -v 'a b' | parallel rm
เซบาสเตียน

1
มันไม่ได้เป็นเพียงแค่พื้นที่ก็ช่องว่างและการขึ้นบรรทัดใหม่ แต่ตัวละครยัง quoting (เดี่ยว, คู่และคำพูดทับขวา) -และชื่อไฟล์ที่เริ่มต้นด้วย
Stéphane Chazelas

32

รักษาสำเนาลบทุกอย่างคืนค่าสำเนา:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR

ในหนึ่งบรรทัด:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

แต่นั่นต้องใช้เชลล์ที่รองรับสตริงที่นี่


10
นี่ค่อนข้างน่าเหลือเชื่อ
vschum

2
@Derek - โปรดดูการแก้ไข
mikeserv

2
แต่ถ้าสิ่งนี้ถูกขัดจังหวะครึ่งทางหรือหากมีสิ่งใดผิดพลาดไฟล์จะหายไป
kasperd

2
@kasperd - ไม่ เฉพาะในกรณีที่ผู้ปกครองเปลือกตายระหว่างช่วงเวลาที่มันจะทำงานและrm สามารถล้มเหลวได้มากเท่าที่ต้องการ tar -xrm
mikeserv

2
การย้ายไปยังไดเรกทอรีอื่นมีประสิทธิภาพมากกว่าหรือไม่ เราไม่จำเป็นต้องจัดการกับเนื้อหาของไฟล์เฉพาะเส้นทางของมัน
leonbloy

23

คุณคิดมากเรื่องนี้

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/

เสร็จสิ้น

แก้ไขจริงง่ายกว่า:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/

3
นั่นคือสิ่งเดียวกันกับที่ฉันตอบ exce [pt มันจะไม่สูญเสียสิทธิ์ใด ๆ ใน dir
mikeserv

6
หากเป็นไฟล์ขนาดใหญ่ในระบบไฟล์แยกจาก / tmp และคุณพยายามลบทุกอย่างออกจากรูทของระบบไฟล์ลงการย้ายไฟล์ไปที่ที่ปลอดภัยอาจไม่ใช่ตัวเลือก
จอห์นนี่

1
นี่เป็นคำตอบที่ง่ายที่สุดแน่นอน
Ben Liyanage

17

บน Scientific Linux 6 OS ของฉันสามารถใช้งานได้:

shopt -s extglob
rm !(file.txt)

ฉันยังมี Debian 32 บิตติดตั้งบนเครื่องเสมือน ข้างต้นไม่ทำงาน แต่ต่อไปนี้จะไม่:

find . -type f ! -name 'file.txt' -delete

1
คุณหมายถึงfindทางออกที่ฉันให้ไม่ทำงานเหรอ?
cuonglm

"ไม่ทำงาน" หรือ "ไม่ทำงาน" ใช่วิธีการแก้ปัญหาการค้นหาของคุณยังใช้งานได้ ขอบคุณ
Kantura

1
คุณสามารถเพิ่มรายละเอียดเพิ่มเติมได้หรือไม่? ทำงานอย่างไร "ไม่ทำงาน? ไม่ลบไฟล์อื่นหรือลบออกfile.txtหรืออะไรอย่างอื่น?
cuonglm

ฉันหมายความว่าในระบบปฏิบัติการ Debian "$ rm! (file.txt)" ส่งคืน "วางไม่ดี () 's" ดังนั้นฉันจึงลอง "$ shopt -s extglob" แต่มันกลับมา: "shopt: ไม่พบคำสั่ง" จากนั้นฉันลองใช้วิธี "ค้นหา" มันใช้งานได้ดี
Kantura

1
โอ้แน่นอนว่ามันไม่ทำงาน shoptไม่ใช่tcshbuiltin
cuonglm

10

ใช้rm !("file.txt")แทนrm !(file.txt)


4
นั่นทำให้ไม่มีความแตกต่างอย่างแน่นอน ปัญหาที่นี่คือการที่ OP คือ 1) ไม่ได้ใช้เปลือกที่สนับสนุนรูปแบบนี้และ 2) shopt -s extglobแม้ในทุบตีคุณจะต้องเปิดใช้งานได้ด้วย ไม่ว่าในกรณีใดการอ้างชื่อไฟล์แบบง่าย ๆ แบบนั้นคงไม่ทำให้เกิดความแตกต่าง
terdon

1
เพื่อให้โฟลเดอร์ utils เพียงทำ - rm -rf! ("utils")
James Jithin

7

เพียงให้คำตอบที่ต่างออกไปคุณสามารถใช้การทำงานเริ่มต้นrmซึ่งจะไม่ลบโฟลเดอร์:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir

1

ฉันพบว่าวิธีนี้ง่ายมากใช้งานได้และไม่ต้องการส่วนขยายพิเศษใด ๆ (ที่ฉันรู้!)

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