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


36

ฉันต้องลบไฟล์ทั้งหมดที่มีนามสกุล. gif ยกเว้นไฟล์เดียวที่มีชื่อว่า "filename.gif" วิธีที่ดีที่สุดในการทำสิ่งนี้ใน terminal คืออะไร?

RM คำสั่ง*.gifลบไฟล์ GIF filename.gifทั้งหมดรวมทั้งไฟล์

คำตอบ:


66

นี่เป็นวิธีง่ายๆที่คุณควรใช้:

mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif

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

หากคุณไม่ต้องเปลี่ยนชื่อไฟล์ (และมีสถานการณ์การเขียนสคริปต์ที่มีความสำคัญ):

for X in *.gif; do
    if [ "$X" != "filename.gif" ]; then
        rm "$X"
    fi
done

หรือคุณเขียนมันสั้นกว่านี้:

for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done

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

find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete

ฉันใช้-notโอเปอเรเตอร์เพื่อการอ่าน แต่ถ้าPOSIXมีความสำคัญ - ถ้าคุณไม่ได้ใช้ GNU find หรือถ้านี่เป็นสคริปต์ที่คุณต้องการแจกจ่ายต่อให้ผู้อื่นหรือทำงานในระบบที่หลากหลาย - คุณควร ใช้!โอเปอเรเตอร์แทน:

find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete

สิ่งหนึ่งที่มีประโยชน์เกี่ยวกับfindคือคุณสามารถปรับเปลี่ยนคำสั่งสำหรับ case-insensitivity ได้อย่างง่ายดายเพื่อให้สามารถค้นหาและลบไฟล์ที่มีนามสกุลเช่น.GIF:

find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete

โปรดทราบว่าผมเคยใช้-inameในสถานที่ของ-nameสำหรับรูปแบบการค้นหา*.gifแต่ฉันยังไม่ได้filename.gifใช้มัน สันนิษฐานว่าคุณรู้แน่ชัดว่าไฟล์ของคุณมีชื่อว่าอะไรและ-inameจะจับคู่กับการใช้อักษรตัวพิมพ์ใหญ่ไม่เพียง แต่ในส่วนขยายแต่ทุกที่ในชื่อไฟล์

โซลูชันทั้งหมดเหล่านี้จะลบไฟล์ที่อยู่ในไดเรกทอรีปัจจุบันทันที พวกเขาจะไม่ลบไฟล์ที่ไม่มีอยู่ในไดเรกทอรีปัจจุบันและพวกเขาจะไม่ลบไฟล์ที่อยู่ในไดเรกทอรีย่อยของไดเรกทอรีปัจจุบัน

หากคุณต้องการลบไฟล์ทุกที่ที่มีอยู่ภายในไดเรกทอรีปัจจุบัน (นั่นคือรวมถึงในไดเรกทอรีย่อยและในไดเรกทอรีย่อยของไดเรกทอรีย่อยเหล่านั้นและอื่น ๆ - ไฟล์ที่มีอยู่ในไดเรกทอรีปัจจุบันหรือลูกหลานของมัน) find โดยไม่ต้อง ใช้maxdepth -1:

find . -not -name 'filename.gif' -name '*.gif' -delete

ระวังด้วย!

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

find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete

เพียงให้แน่ใจว่าคุณไม่เคยใส่-deleteก่อนหน้าการแสดงออกอื่น คุณจะเห็นว่าฉันอยู่-deleteท้ายที่สุด ถ้าคุณวางไว้ที่จุดเริ่มต้นก็จะได้รับการประเมินครั้งแรกและทุกไฟล์ที่อยู่ภายใต้.(รวมถึงไฟล์ที่ไม่สิ้นสุดใน.gifและไฟล์ในลึกย่อยย่อย ... ไดเรกทอรีของ.) จะถูกลบ!

สำหรับข้อมูลเพิ่มเติมโปรดดูที่หน้าคู่มือสำหรับbashและshและสำหรับคำสั่งที่ใช้ในตัวอย่างเหล่านี้: mv, rm, [และ find(โดยเฉพาะ)


1
ขอบคุณ Eliah ฉันทำมันคล้ายกับวิธีแรกที่คุณแนะนำคือการแปลงไฟล์ในรูปแบบที่แตกต่างและแปลงกลับ แต่ดูเหมือนว่าย่อยดีที่สุดและไม่สะอาด ฉันชอบแนวทางที่สองที่คุณและ @efthialex ได้แนะนำและฉันกำลังใช้งานอยู่ตอนนี้ ขอบคุณ!

1
@ Marvis ฉันดีใจที่สิ่งนี้ตอบสนองความต้องการของคุณ อย่างไรก็ตามฉันได้ขยายคำตอบนี้ด้วยข้อมูลเกี่ยวกับวิธีอื่น (หรือคลาสของวิธีการ) โดยใช้findซึ่งมีประโยชน์อย่างมาก
Eliah Kagan

3
ขอบคุณสำหรับคำตอบโดยละเอียดfindย่อมเป็นการค้นหาที่ดี

1
+1 สำหรับคำตอบทั่วไป (move-delete-move)
tu-Reinstate Monica-dor duh

Nit-pick: วิธีfindจัดการกับชื่อไฟล์แปลก ๆ*ในนั้นดีกว่า for-loop อย่างไร สำหรับห่วงจัดการไฟล์ได้*ดีเพราะคุณใช้เครื่องหมายคำพูดคู่
Flimm

28

หากคุณกำลังใช้bash(เชลล์เริ่มต้น) extglobตัวเลือกเชลล์จะช่วยให้คุณใช้ไวยากรณ์การจับคู่รูปแบบเพิ่มเติม หากต้องการเปิดใช้งานให้ใช้shoptคำสั่ง builtin:

shopt -s extglob

(ฉันรวมบรรทัดนั้นไว้ใน.bashrcไฟล์ของฉัน)

เหนือสิ่งอื่นใดมันมอบสิทธิ์การเข้าถึง!()โอเปอเรเตอร์ซึ่งตรงกับลวดลายใด ๆ เพื่อจุดประสงค์ของคุณ:

rm !(filename).gif

ข้อมูลเพิ่มเติมมีอยู่ในman bash"การจับคู่รูปแบบ"


1
คำตอบที่ยอดเยี่ยม! เป็นเฉพาะสำหรับทุบตีดังนั้นอาจไม่เหมาะสำหรับการเขียนสคริปต์แบบพกพา แต่งานแบบโต้ตอบและแม้แต่การเขียนสคริปต์บางอย่างนี่เป็นวิธีที่ดีที่สุดในการลงมือทำ มันมีความซับซ้อนเพิ่มที่extglobต้องเปิดใช้งาน แต่ไม่มีอะไรเลวร้ายเกิดขึ้นถ้ามันถูกปิดการใช้งาน (ในกรณีนี้มันก็ไม่ทำงาน) และดูเหมือนว่าจะเปิดใช้งานตามค่าเริ่มต้นแม้ว่าฉันจะไม่มีshopt -s extglobไฟล์การกำหนดค่า (หรือระดับโลก) ก็ตาม หากมีคำอธิบายง่ายๆว่าทำไมมันถึงใช้ได้กับฉันนอกกรอบคุณอาจต้องการเพิ่มคำตอบนี้ หรือฉันอาจโพสต์คำถามใหม่
Eliah Kagan

13

เปิดTerminalด้วยCtrl+ Alt+ Tและพิมพ์:

find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;

ความแตกต่างระหว่าง-deleteและ-exec rm -vf {} \;คือกับตัวเลือกที่สองคุณจะสามารถดูไฟล์ที่ถูกลบเนื่องจากการ-vตั้งค่าสถานะ นั่นเป็นสิ่งที่ไม่สามารถทำได้ด้วย-deleteตัวเลือก ( -name -deleteจะพิมพ์ชื่อไฟล์ แต่rmกับ-vเผยถ้าแต่ละไฟล์ได้รับการประสบความสำเร็จลบ.)


1

มีGLOBIGNOREตัวแปร จากman bash:

GLOBIGNORE
      A colon-separated list of patterns defining the set of filenames
      to be ignored by pathname expansion.  If a filename matched by a
      pathname expansion pattern also matches one of the  patterns  in
      GLOBIGNORE, it is removed from the list of matches.

ดังนั้นวิธีง่ายๆคือตั้งค่าGLOBGINOREชื่อไฟล์ที่เป็นปัญหา:

$ touch {a,b,c,d}.png
$ echo *.png
a.png b.png c.png d.png
$ GLOBIGNORE=c.png
$ echo *.png
a.png b.png d.png

ดังนั้นในกรณีของคุณ:

GLOBIGNORE=filename.gif; rm *.gif

แน่นอนเนื่องจากGLOBIGNOREมีรูปแบบคุณสามารถใช้ทุกครั้งที่คุณต้องการยกเว้นรูปแบบ:

$ GLOBIGNORE='[a-c].png'; echo *.png
d.png
$ touch bd.png; GLOBIGNORE='?.png'; echo *.png
bd.png

ข้อได้เปรียบ (?!) ของGLOBIGNOREคือการตั้งค่าจะแยก.และ..จากการจับคู่โดยอัตโนมัติและจะช่วยให้dotglob:

The  GLOBIGNORE shell variable may be used to restrict the set of file‐
names matching a pattern.  If GLOBIGNORE is set, each matching filename
that also matches one of the patterns in GLOBIGNORE is removed from the
list of matches.  The filenames ``.''  and ``..''  are  always  ignored
when  GLOBIGNORE is set and not null.  However, setting GLOBIGNORE to a
non-null value has the effect of enabling the dotglob shell option,  so
all other filenames beginning with a ``.''  will match.  To get the old
behavior of ignoring filenames beginning with a ``.'', make ``.*''  one
of  the  patterns  in  GLOBIGNORE.  The dotglob option is disabled when
GLOBIGNORE is unset.

ดังนั้นวิธีที่ง่ายในการลบทุกไฟล์และโฟลเดอร์ในไดเรกทอรี:

GLOBIGNORE=.; rm -r *

*จะตรงกับชื่อไฟล์ที่เริ่มต้นด้วย.ตั้งแต่GLOBIGNOREเปิดใช้งานdotglobแต่มันจะไม่ตรง.หรือ..ดังนั้นคุณจะไม่ส่งผลกระทบไดเรกทอรีแม่ว่าวิธีการ

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