ยกเว้นหนึ่งรูปแบบจากการจับคู่แบบกลม


53

ฉันมีหลายไฟล์ที่มีชื่อไฟล์ฐานเดียวกัน ฉันต้องการลบทั้งหมดยกเว้นหนึ่งรายการ

foo.org #keep
foo.tex #delete
foo.fls #delete
foo.bib #delete
etc

หากฉันไม่ต้องการเก็บไว้ฉันรู้ว่าฉันสามารถrm foo.*ใช้ได้

TLDPสาธิต^การคัดค้านการแข่งขัน จากการทดลองและข้อผิดพลาดฉันสามารถค้นพบสิ่งนั้นได้

rm foo.*[^org]

ทำในสิ่งที่ฉันต้องการ แต่ฉันไม่เข้าใจไวยากรณ์

นอกจากนี้ในขณะที่ไม่ได้เป็นข้อ จำกัด ในกรณีที่ใช้งานของฉันฉันคิดว่ารูปแบบนี้ยังไม่สนใจและfoo.o foo.orรูปแบบนี้ทำงานอย่างไรและรูปทรงแบบใดที่ละเว้นเพียง foo.orgดูเหมือน


1
ที่นอกเหนือไป @glen ตอบมันคุ้มค่าที่จะพูดถึงว่าrm foo.*[^org]ลบไฟล์ทั้งหมดที่ผ่านมาของตัวละครจะไม่o, rหรือgดังนั้นfoo.fooจะไม่ตรงกับอย่างใดอย่างหนึ่ง
jimmij

Regular Expressionคุณกำลังใช้ คุณควรระวังตัวละครจัดกลุ่มของคุณ โดยใช้วงเล็บคุณได้ระบุความหมายชั้นเรียนตัวอักษรที่คุณจะลบไฟล์ใด ๆ ที่มีส่วนขยายด้วยตัวอักษรo, rหรือgในลำดับใด ใช้วงเล็บเพื่อสร้างกลุ่มและรักษาลำดับของอักขระ
Mr. Mascaro

3
@ jbarker2160 - นั่นไม่ใช่การแสดงออกปกติโดยทั่วไปเรียกว่าglob (หรือรูปแบบชื่อไฟล์ ) ซึ่งมากกว่าหรือน้อยกว่าชุดย่อยของการแสดงออกปกติ - ดูส่วนการจับคู่รูปแบบของ manpage ทุบตีเพื่อดูรายละเอียด รูปแบบของเขาfoo.*[^org]จะตรงกับชื่อไฟล์ใด ๆ ที่ขึ้นต้นด้วยfoo.อักขระหนึ่งตัวขึ้นไปหลังจากจุดที่อักขระสุดท้ายไม่ใช่ o, r หรือ g ดังนั้นจึงจะตรงfoo.orbแต่ไม่foo.orgหรือหรือfoo.or foo.oคำตอบของ GlennJackman แสดงวิธีเปิดใช้งานคุณสมบัติการจับคู่รูปแบบเพิ่มเติมเพื่อคัดค้านการจับคู่
Johnny

คำตอบ:


52
shopt -s extglob
echo rm foo.!(org)

นี่คือ "foo" ตามด้วยสิ่งใดที่ไม่ใช่ "org"

อ้างอิง: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching


ฉันพยายามทำเหมือนกัน แต่มีวงเล็บและเห็นได้ชัดเมื่อใช้วงเล็บมันไม่ทำงาน
Donato

4
ไวยากรณ์ในการจับคู่ชื่อไฟล์หลายชื่อคืออะไร ว่าฉันต้องการยกเว้น. org, .png, .txt หรือไม่
Freedo

@ เฟรโด้@()สำหรับรายการรูปแบบ: stackoverflow.com/a/217208/3779853
phil294

23

GLOBIGNORE="*.org"; rm -i foo*ในทุบตีคุณยังสามารถใช้

และunset GLOBIGNOREเมื่อเสร็จแล้ว

มันไม่ได้ดีไปกว่าshopt -s extglobนี้ แต่ฉันพบว่าจดจำได้ง่ายกว่า


5
@ Ruslan มันใช้งานไม่ได้ คุณควรทำ( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko

3
หมายเหตุหากคุณต้องการขยายรายการที่ถูกละเว้นให้คั่นด้วยเครื่องหมายจุดคู่เช่นGLOBIGNORE="*foo*:*bar*"
phyatt

7

ท่อสามารถทำอะไรได้บ้าง

ls * | grep -v "foo.org" | xargs -I {} echo {}

(เห็นได้ชัดว่าคุณอาจต้องการแทนที่เสียงก้องด้วย rm ในห่วงโซ่สุดท้าย)


มีประโยชน์ถ้าจำเป็นในหนึ่งบรรทัด
bruceskyaus

1
ง่ายต่อการจดจำ (สำหรับฉันฉันทำเรียงลำดับของสิ่งที่มักจะ) และช่วยให้การประมวลผลที่ซับซ้อนมากขึ้นในการบูต :)
drevicko

1
ls -1ควรเชื่อถือได้มากกว่าเพื่อให้มั่นใจว่าไฟล์ทั้งหมดจะได้รับการจัดการgrepแยกต่างหาก
MichaelChirico

0

OP อยู่ใกล้มาก:

rm foo.*[^o][^r][^g]

แม้ว่าในกรณีนี้*มันไม่จำเป็น

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