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


215

เมื่อใช้sudo rm -rงานฉันจะลบไฟล์ทั้งหมดได้อย่างไรด้วยข้อยกเว้นต่อไปนี้:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
ดูเหมือนคำถามสำหรับunix.stackexchange.com
Jason

1
มี 2 ​​วิธีในการอ่านคำถามนี้และคำตอบที่มีอยู่ครอบคลุมการตีความทั้งสอง: EITHER: (a) สงวนไฟล์ด้วยชื่อที่ระบุโดยตรงในไดเรกทอรีเป้าหมายและ - ตามที่rm -rบอก - ลบทุกอย่างรวมถึงไดเรกทอรีย่อยแม้ว่าจะมี ไฟล์ที่มีชื่อที่ระบุ OR: (b) สำรวจทรีย่อยทั้งหมดของไดเรกทอรีเป้าหมายและในแต่ละไดเรกทอรีให้ลบไฟล์ทั้งหมดยกเว้นที่มีชื่อในรายการ
mklement0

คำตอบ:


219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

หากคุณไม่ระบุ-type ffind จะแสดงรายการไดเรกทอรีซึ่งคุณอาจไม่ต้องการ


หรือวิธีแก้ปัญหาทั่วไปเพิ่มเติมโดยใช้ชุดค่าผสมที่มีประโยชน์มากfind | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

ตัวอย่างเช่นลบไฟล์ txt ที่ไม่ใช่ทั้งหมดในไดเรกทอรีปัจจุบัน:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

print0และ-0รวมกันเป็นสิ่งจำเป็นหากมีช่องว่างในใด ๆ ของชื่อไฟล์ที่ควรจะถูกลบ


2
ดูเหมือนว่า xargs จะมีการ จำกัด ขนาดข้อความ
frazras

26
เพื่อลบหลายรูปแบบ:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen 申思维

5
สิ่งที่เกี่ยวกับไดเรกทอรี? มันจะลบไฟล์ทั้งหมด แต่จะลบโฟลเดอร์หรือไม่!
orezvani

31
แทนที่จะเป็น "| xargs rm" find จะใช้พารามิเตอร์ -delete
Emil Stenström

1
แทนที่จะทำอย่าง-print0 | xargs -0 rm --นั้น-delete
Andy

151
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

ต้องเปิดใช้งาน extglob (การจับคู่รูปแบบขยาย) ใน BASH (หากไม่ได้เปิดใช้งาน):

shopt -s extglob

2
ฉันได้รับ "ข้อผิดพลาดทางไวยากรณ์ใกล้กับโทเค็นที่ไม่คาดคิด` ('"เมื่อฉันทำความshopt -s extglob; rm -rf !(README|LICENSE)คิดใด ๆ ว่าทำไม
Dennis

@nic ฉันจำไม่ได้ขอโทษ ฉันอาจสิ้นสุดที่ใช้findกับ-deleteตัวเลือก
Dennis

นี่เป็นทางออกที่ดีที่สุดสำหรับฉันและทำงานตามค่าเริ่มต้นบน Ubuntu 12.04.4 LTS ของฉันโดยไม่จำเป็นต้องซื้อสินค้า
xtian

3
@nic, @Dennis: ข้อผิดพลาดทางไวยากรณ์แสดงให้เห็นว่ามีสิ่งอื่น ๆ ที่bashถูกใช้เช่นdashที่extglobไม่ได้รับการสนับสนุน อย่างไรก็ตามในเชลล์แบบโต้ตอบ bashคำสั่งจะไม่ทำงานตามที่ระบุไว้ แต่ด้วยเหตุผลที่แตกต่างกัน สั้น ๆ ของมัน: ดำเนินการโดยshopt -s extglobITSELF; เมื่อเปิดใช้ประสบความสำเร็จ (ตรวจสอบกับshopt extglob) rm -rf !(README|LICENSE)ดำเนินการ (ขณะที่extglobยังไม่เปิดใช้งาน!(...)จะถูกประเมินโดยการขยายประวัติก่อนที่คำสั่งจะถูกดำเนินการเนื่องจากอาจเป็นไปไม่ได้คำสั่ง NEITHER จะถูกดำเนินการและextglobไม่เคยเปิดใช้)
mklement0

2
@nic, @Dennis, @ mklement0: ฉันมีปัญหาเดียวกันกับ "ข้อผิดพลาดทางไวยากรณ์ใกล้กับโทเค็นที่ไม่คาดคิด (" เมื่อเรียกใช้คำสั่งภายในไฟล์. sh (#! / bin / bash) แต่ไม่ใช่เมื่อฉันเรียกใช้ในคำสั่ง line interface มันกลับกลายเป็นว่านอกเหนือจากการshopt -s extglobรันในอินเตอร์เฟสบรรทัดคำสั่งฉันต้องรันใหม่อีกครั้งภายในไฟล์สคริปต์ของฉันสิ่งนี้แก้ปัญหาให้ฉันได้แล้ว
Ahresse

41

find . | grep -v "excluded files criteria" | xargs rm

วิธีนี้จะแสดงรายการไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันจากนั้นแสดงรายการไฟล์ทั้งหมดที่ไม่ตรงกับเกณฑ์ของคุณ (ระวังการจับคู่ชื่อไดเรกทอรี) แล้วลบออก

อัปเดต : ขึ้นอยู่กับการแก้ไขของคุณหากคุณต้องการลบทุกอย่างออกจากไดเรกทอรีปัจจุบันยกเว้นไฟล์ที่คุณอยู่ในรายการคุณสามารถใช้สิ่งนี้ได้:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

มันจะสร้างไดเรกทอรีสำรอง/tmp_backup(คุณมีสิทธิ์รูทใช่ไหม) ย้ายไฟล์ที่คุณอยู่ในไดเรกทอรีนั้นลบทุกอย่างซ้ำ ๆ ในไดเรกทอรีปัจจุบัน (คุณรู้ว่าคุณอยู่ในไดเรกทอรีที่ถูกต้องใช่ไหม?) ย้าย กลับไปทุกอย่างจากไดเรกทอรีปัจจุบันและในที่สุดก็ลบ/tmp_backup/tmp_backup

ฉันเลือกไดเรกทอรีสำรองที่จะอยู่ในรูทเพราะถ้าคุณพยายามที่จะลบทุกอย่างจากรากซ้ำระบบของคุณจะมีปัญหาใหญ่

แน่นอนว่ามีวิธีที่สง่างามกว่าในการทำเช่นนี้ แต่อันนี้ค่อนข้างตรงไปตรงมา


2
ทำงานได้ดีกับ egrep เช่นสำหรับการทำความสะอาดไฟล์ลาเท็กซ์ระดับกลาง:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz

คำสั่งที่น่าทึ่ง! สำหรับการลบไดเรกทอรีเพียงเปลี่ยนเป็น rm -r
Aris

1
หากคุณต้องการลบทุกอย่างในไดเรกทอรีปัจจุบันนอกเหนือจากเกณฑ์ที่แยกออก: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rทำงานได้เร็วขึ้นมากเนื่องจากไม่จำเป็นต้องเจาะลึกไดเรกทอรีต่างๆโดยไม่จำเป็น
billynoah

findไปป์ไลน์อีกครั้ง: ปัญหาด้านประสิทธิภาพ (3 คำสั่งใช้สำหรับสิ่งที่findทำได้โดยลำพัง) สิ่งนี้จะไม่ทำงานตามที่ต้องการด้วยชื่อไฟล์ที่มีช่องว่างในตัวและอาจลบไฟล์ผิด
mklement0

คำสั่งที่ร้านค้า "เพื่อที่จะบันทึกไฟล์" ในสถานที่อื่น ( /tmp_backup) ไม่ได้จบกันถ้ามันขัดจังหวะจากมุมมองของผู้ใช้ทุกไฟล์ที่ได้หายไปจนกว่าพวกเขาจะทราบว่าจะไปหาพวกเขาที่จะได้รับพวกเขากลับมา . ด้วยเหตุนี้ฉันจึงไม่ชอบกลยุทธ์ประเภทนี้
Craig McQueen

20

สมมติว่าไฟล์ที่มีชื่อเหล่านั้นมีอยู่ในหลาย ๆ ที่ในแผนผังไดเร็กทอรีและคุณต้องการสงวนไฟล์ทั้งหมด

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete

19

คุณสามารถใช้ตัวแปรสภาพแวดล้อม GLOBIGNORE ใน Bash

สมมติว่าคุณต้องการลบไฟล์ทั้งหมดยกเว้น php และ sql จากนั้นคุณสามารถทำดังต่อไปนี้ -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

การตั้งค่า GLOBIGNORE เช่นนี้จะไม่สนใจ php และ sql จาก wildcard ที่ใช้เช่น "ls *" หรือ "rm *" ดังนั้นการใช้ "rm *" หลังจากตั้งค่าตัวแปรจะลบเฉพาะไฟล์ txt และ tar.gz


6
+1; ทางเลือกที่ง่ายกว่าสำหรับการตั้งค่าและการกู้คืนGLOBIGNOREตัวแปรคือการใช้ subshell:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0

19

ฉันชอบที่จะใช้รายการแบบสอบถามย่อย:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, - สลับการจับคู่เลือกบรรทัดที่ไม่ตรงกัน

\| เครื่องสกัด


1
ทางออกที่หรูหรา
Joshua Salazar

9

เนื่องจากไม่มีใครพูดถึงมัน:

  • คัดลอกไฟล์ที่คุณไม่ต้องการลบในที่ปลอดภัย
  • ลบไฟล์ทั้งหมด
  • ย้ายไฟล์ที่คัดลอกกลับเข้าที่

2
มันซับซ้อนกว่าเพราะคุณต้องดูแลสิทธิ์หลังจากที่คุณคัดลอกกลับมา
Romulus

2
@RemusAvram คุณสามารถใช้สวิตช์ที่เหมาะสมกับcpหรือrsyncเพื่อสงวนสิทธิ์ อย่างไรก็ตามนี่เป็นเพียงวิธีอื่น (ให้เป็นคำแนะนำ) ที่มีที่นี่เป็นคำตอบสำหรับ OP
gniourf_gniourf

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

@codeforester: แน่นอน แต่มีสถานการณ์ที่มันเหมาะสม แต่ ... :)ในความเป็นจริงผมไม่เห็นจุดของความคิดเห็นของคุณ
gniourf_gniourf


6

สายไปหน่อยสำหรับ OP แต่หวังว่าจะมีประโยชน์สำหรับทุกคนที่มาที่นี่ในภายหลังโดย google ...

ฉันพบคำตอบโดย @awi และแสดงความคิดเห็นเกี่ยวกับ -delete โดย @Jamie Bullock มีประโยชน์จริงๆ ยูทิลิตี้ง่าย ๆ เพื่อให้คุณสามารถทำได้ในไดเรกทอรีต่าง ๆ โดยไม่สนใจชื่อ / ประเภทไฟล์ที่แตกต่างกันในแต่ละครั้งด้วยการพิมพ์เพียงเล็กน้อย:

rm_except (หรืออะไรก็ตามที่คุณต้องการตั้งชื่อ)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

เช่นการลบทุกอย่างยกเว้นไฟล์ข้อความและ foo.bar:

rm_except *.txt foo.bar 

คล้ายกับ @mishunika แต่ไม่มีประโยคถ้า


5

หากคุณกำลังใช้zshซึ่งฉันขอแนะนำ

rm -rf ^file/folder pattern to avoid

กับ extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

ลองใช้กับ:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

แต่ชื่อที่มีช่องว่างนั้นยาก (เช่นเคย) พยายามด้วยVirtualbox\ VMsคำพูดแทน มันจะลบไดเรกทอรีนั้นเสมอ ( Virtualbox VMs)


ไม่ทำงานกับไฟล์ rm !(myfile.txt)ลบทั้งหมดรวมถึงmyfile.txt
khaverim

ควรดำเนินการshopt -s extglobครั้งแรกเป็น @ pl1nk ชี้ให้เห็น
zhuguowei

ใช่มันเป็นสิ่งสำคัญมากที่จะเปิดใช้งานการขยายแบบวงกลม ( extglob ) ในการทุบตีฉันกำลังทำสิ่งนี้เป็นประจำทุกวันมากกว่า Macs สองสามตัวในห้องทดลอง: shopt -s extglobจากนั้นcd /Users/alumno/และในที่สุดrm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) อ่านเกี่ยวกับการขยายตัวแบบ
วงกลม

4

แค่:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

หรือ:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

ไม่แนะนำ การแยกวิเคราะห์lsผลลัพธ์อาจกลายเป็นปัญหาได้ ดูที่นี่สำหรับข้อมูลรายละเอียด
RJ

2

ทำให้ไฟล์ไม่เปลี่ยนรูป แม้แต่รูทจะไม่ได้รับอนุญาตให้ลบ

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

ไฟล์อื่นทั้งหมดถูกลบไปแล้ว
ในที่สุดคุณสามารถรีเซ็ตพวกเขาไม่แน่นอน

chattr -i *

0

สิ่งนี้คล้ายกับความคิดเห็นจาก @ siwei-shen แต่คุณต้องการให้-oแฟล็กทำหลายรูปแบบ -oธงย่อมาจาก 'หรือ'

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

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

files=( backup.tar.gz script.php database.sql info.txt )

หลังจากนั้นวนไฟล์ทั้งหมดในไดเรกทอรีที่คุณต้องการแยกตรวจสอบว่าชื่อไฟล์อยู่ในอาร์เรย์ที่คุณไม่ต้องการแยกออกหรือไม่ หากยังไม่ได้ลบไฟล์

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

การเปรียบเทียบ regex ไม่ถูกต้อง - มันจะเก็บรักษาไฟล์ใด ๆ ที่มีชื่อเป็นซับสตริงของหนึ่งในไฟล์ที่ได้รับการป้องกัน คุณควรรวบรวมอาเรย์ของไฟล์ทั้งหมดจากนั้นลบไฟล์ที่คุณต้องการแยกออกจากอาเรย์นั้นแล้วลบไฟล์ที่เหลือ
tripleee

-1

เนื่องจากยังไม่มีใครพูดถึงเรื่องนี้ในกรณีพิเศษ:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(หรือเพียงแค่ rm $OLD_FILES )

หรือ

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

คุณอาจจำเป็นต้องใช้shopt -s nullglobถ้าไฟล์บางไฟล์อาจมีหรือไม่มี:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

ไม่มี nullglob echo *.sh *.bashอาจให้ "a.sh b.sh * .bash"

(ต้องบอกว่าทั้งหมดฉันเองชอบคำตอบนี้แม้ว่าจะไม่ทำงานใน OSX)


คำตอบที่มีอยู่โดย Leonardo Hermoso ทำสิ่งนี้ด้วยข้อบกพร่องน้อยลง สิ่งนี้จะล้มเหลวสำหรับชื่อไฟล์ที่มีช่องว่าง การใช้อาร์เรย์ช่วยแก้ปัญหานั้นได้อย่างสวยงาม (และยังหลีกเลี่ยงการใช้ตัวพิมพ์ใหญ่สำหรับตัวแปรส่วนตัวของเขาซึ่งโดยทั่วไปจะต้องหลีกเลี่ยง)
tripleee

-3

แทนที่จะไปสำหรับคำสั่งโดยตรงโปรดย้ายไฟล์ที่ต้องการไปที่ temp dir นอก dir ปัจจุบัน จากนั้นลบไฟล์ทั้งหมดโดยใช้rm *หรือrm -r *หรือ

จากนั้นย้ายไฟล์ที่ต้องการไปยัง dir ปัจจุบัน


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

-3

ลบทุกอย่างยกเว้นไฟล์ชื่อ:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

2
สิ่งนี้จะล้มเหลวอย่างน่ากลัวและอาจทำให้ข้อมูลสูญหายหากไดเรกทอรี / ไฟล์ของคุณมีช่องว่างหรือตัวอักษรผิดปกติ คุณไม่ควรแยกคำ ls mywiki.wooledge.org/ParsingLs
RJ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.