ลบโฟลเดอร์ทั้งหมดภายในโฟลเดอร์ยกเว้นที่มีชื่อเฉพาะ


18

ฉันต้องการลบโฟลเดอร์ทั้งหมดภายในโฟลเดอร์โดยใช้สคริปต์รายวัน ต้องทิ้งโฟลเดอร์ในวันนั้น

โฟลเดอร์ 'myfolder' มี 3 โฟลเดอร์ย่อย: 'test1', 'test2' และ 'test3' ฉันต้องลบทั้งหมดยกเว้น 'test2'

ฉันพยายามจับคู่ชื่อที่แน่นอนที่นี่:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

หรือ

find /home/myfolder -type d ! -name 'test2' -delete

คำสั่งนี้จะพยายามลบโฟลเดอร์หลัก 'myfolder' ด้วยเสมอ! มีวิธีหลีกเลี่ยงสิ่งนี้หรือไม่?


6
ใน Unix และ Linux เราเรียก "ไดเรกทอรี" เหล่านี้ไม่ใช่ "โฟลเดอร์"
tchrist

1
ทั้งนี้ขึ้นอยู่กับเปลือกของคุณคุณอาจจะต้องพูดว่า!ผู้ประกอบการ: หรือ\! '!'
Toby Speight

คำตอบ:


32

การดำเนินการนี้จะลบโฟลเดอร์ทั้งหมด./myfolderยกเว้นว่า./myfolder/test2เนื้อหาทั้งหมดจะถูกเก็บไว้:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

มันทำงานอย่างไร

  • find เริ่มคำสั่ง find
  • ./myfolderบอกให้ค้นหาเริ่มต้นด้วยไดเรกทอรี./myfolderและเนื้อหา

  • -mindepth 1 เพื่อไม่ให้ตรงกับ./myfolderตัวเองเพียงไฟล์และไดเรกทอรีภายใต้

  • ! -regex '^./myfolder/test2\(/.*\)?' บอกหาเพื่อยกเว้น ( !) ไฟล์หรือไดเรกทอรีใด ๆ ^./myfolder/test2\(/.*\)?ที่ตรงกับการแสดงออกปกติ ^ตรงกับจุดเริ่มต้นของชื่อเส้นทาง การแสดงออก (/.*\)?ตรงกับ (a) สแลชตามด้วยอะไรหรือ (b) ไม่มีอะไรเลย

  • -delete บอกให้ค้นหาลบไฟล์ที่ตรงกัน (นั่นคือไม่รวมอยู่)

ตัวอย่าง

พิจารณาโครงสร้างไดเรกทอรีที่ดูเหมือนว่า;

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

เราสามารถเรียกใช้คำสั่ง find (ไม่ใช้-delete) เพื่อดูว่าตรงกับอะไร:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

เราสามารถตรวจสอบว่ามันใช้งานได้โดยดูไฟล์ที่เหลืออยู่:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

1
ทางเลือกในการ-pruneที่จะออกจากtest2/*/ไดเรกทอรีย่อยเพียงอย่างเดียว: กลับไปและเพิ่มrm -r -maxdepth 1
Toby Speight

@Isaac ตกลง เสร็จสิ้น (เช่น +1 สำหรับคำตอบที่ยอดเยี่ยมของคุณ)
John1024

ทำงานที่ยอดเยี่ยม !, แต่ขออภัย: ที่จะลบทุกไฟล์./myfolderที่อยู่ภายใน คุณจำเป็นต้องมีขาดหายไป (IMvhO) -type dสำหรับไดเรกทอรีเท่านั้น
NotAnUnixNazi

ตกลงสิ่งนี้จะทำงานได้ตามที่คุณต้องการ:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
NotAnUnixNazi

10

ใช้ทุบตี :

shopt -s extglob
rm -r myfolder/!(test2)/

ตัวอย่าง:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file

5

TL; DR

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

ลบเสียงก้องถ้าพอใจกับรายชื่อไฟล์


การใช้-mindepth 1จะทำให้แน่ใจว่าไม่ได้เลือกไดเรกทอรีบนสุด

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

แต่-not -name test2จะไม่หลีกเลี่ยงตำบลภายในtest2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

ในการทำเช่นนั้นคุณต้องมีลูกพรุน:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

แต่อย่าใช้deleteเพราะมันหมายถึงdepthและจะเริ่มลบจากเส้นทางที่ยาวที่สุด:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

ใช้อย่างใดอย่างหนึ่งrm -rf(ลบechoหากคุณต้องการลบจริง):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

หรือยังใช้maxdepthถ้าทั้งหมดที่คุณต้องการก็คือการลบไดเรกทอรี (และภายในทุกอย่าง) (ลบechoจริงลบ):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

-deleteจะยังคงล้มเหลวถ้าไดเรกทอรีไม่ว่าง:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty

2

หากคุณใช้ zsh คุณจะสามารถ:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

ทดสอบด้วยคำสั่งด้านล่างและทำงานได้ดี

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;

คุณพบปัญหาเดียวกันกับ OP รายการ / home / โฟลเดอร์บนบรรทัดคำสั่ง (โดยไม่สำคัญ-mindepth 1) ทำให้ไดเรกทอรีบนสุดตรงกับเกณฑ์ทั้งหมด (เป็นไดเรกทอรีและไม่มีชื่อ "test2") และดังนั้นจึงถูกลบ
Jeff Schaller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.