`[!]` (เครื่องหมายอัศเจรีย์ในวงเล็บ) สัญลักษณ์แทนในทุบตี


10

ผมได้มาในรูปแบบ globbing [!]และสัญลักษณ์และน่าสนใจโดยเฉพาะให้ฉันเป็น

สร้างนี้มีความคล้ายคลึงกับ[!]การสร้างยกเว้นมากกว่าที่ตรงกับตัวอักษรใดในวงเล็บก็จะตรงกับตัวอักษรใด ๆ ตราบใดที่มันไม่ได้อยู่ระหว่างและ[]

rm myfile [!192]

ฉันเชื่อว่าข้างต้นจะลบไฟล์ใด ๆ / ทั้งหมดยกเว้นไฟล์ใด ๆ / ทั้งหมดที่มี 192 ในชื่อของพวกเขา

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

สิ่งที่จะเป็นไวยากรณ์ที่เหมาะสมในสถานการณ์เช่นนี้?

rm myfile [!.gif .csv. mp3] 

หรือ

rm myfile [!.gif !.csv !.mp3]

ความกังวลของฉันคือช่วงเวลานั้นอาจถูกวางผิดตำแหน่งและดังนั้นไฟล์ใด ๆ ที่มี.(ซึ่งจะเป็นไฟล์ใดไฟล์หนึ่ง) จะถูกจัดการเมื่อฉันพยายามทำให้เกิดการจัดการไฟล์เฉพาะ

สร้างนี้มีความคล้ายคลึงกับ[ ]การสร้างยกเว้นมากกว่าที่ตรงกับตัวอักษรใดในวงเล็บก็จะตรงกับตัวอักษรใด ๆ ตราบใดที่มันไม่ได้อยู่ระหว่างและ[]

(อ้างจากhttp://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm )

ตอนนี้; สำหรับฉันแล้วแนะนำว่าเอกพจน์!นั้นเพียงพอแล้วและค่าทั้งหมดในนั้นจะอยู่ในช่วง


5
เป็นเคล็ดลับทั่วไปใช้ls my-patternหรือecho my-commandเพื่อตรวจสอบว่า globbing จะทำในแบบที่คุณต้องการก่อนที่จะใช้rm
Wayne_Yux

นอกจากนี้โปรดจำไว้ว่าไฟล์ส่วนใหญ่นั้นถ้าไม่มีส่วนใหญ่จะไม่มีนามสกุล ส่วนขยายบนระบบ Linux มักไม่เกี่ยวข้องและไม่ได้ใช้เพื่อกำหนดประเภทไฟล์ตามโปรแกรมส่วนใหญ่
terdon

2
โปรดทราบว่าคำพูดแรกของคุณถูกอ้างถึงผิดตอนนี้ดูเหมือนว่าโดยทั่วไปแล้วจะบอกว่า[!]คล้ายกัน แต่ไม่ชอบ[!]
ilkkachu

2
เป็นมูลค่าการกล่าวขวัญว่า^มีความหมายเหมือนกัน!ในบริบทนี้ดังนั้นจึง[^a]แยกออกaเหมือน[!a]: ถ้าตัวละครตัวแรกที่ตามหลัง [คือ! หรือ a ^ จากนั้นอักขระที่ไม่ได้อยู่ในเครื่องหมายจะถูกจับคู่ ( man bash)
ของหวาน

3
rm myfile [!192]จะลบmyfileเช่นเดียวกับไฟล์ใด ๆ ตัวเดียวไม่ได้ตั้งชื่อ1, หรือ9 2
เควิน

คำตอบ:


16

อ้างถึงman 7 glob:

An  expression  "[!...]"  matches  a single character, namely any character
that is not matched by the expression obtained by removing the first '!' from it.
(Thus, "[!]a-]" matches any single character except ']', 'a' and '-'.)

เน้นที่ส่วนอักขระเดียวที่นี่[]ไม่สามารถใช้กับสตริงทั้งหมดในการจับคู่รูปแบบ Bash


bashของการขยายตัวรั้งสามารถนำมาใช้เพื่อให้ตรงกับสาย แต่ไม่มีทาง (ฉันรู้) จะลบล้างพวกเขา เช่น

1.{gif,csv,mp3}

ถูกขยายเป็น

1.gif 1.csv 1.mp3

ไม่ว่าไฟล์เหล่านี้จะมีอยู่จริงก็ตาม


ในฐานะที่เป็นwcharginชี้ให้สามารถใช้ในการทำให้ผู้ประกอบการจับคู่รูปแบบการขยายหนึ่งของพวกเขาเป็นshopt !()หลังจากวิ่งshopt -s extglobเช่น

1.!(gif|csv|mp3)

ถูกขยายเป็น

1.jpg 1.bmp 1.png

หากไฟล์เหล่านั้นมีอยู่ในไดเรกทอรีปัจจุบัน สำหรับการอ่านเพิ่มเติมman bash(ส่วนขยาย / การขยายชื่อเส้นทาง) และการขยายชื่อเส้นทาง (การวนซ้ำ)


สำหรับสิ่งที่คุณพยายามทำฉันมักจะใช้findซึ่งมีการปฏิเสธและอื่น ๆ อีกมากมายเช่นในวิธีต่อไปนี้:

find . -maxdepth 1 -type f ! -name "*.gif" -a ! -name "*.csv" -a ! -name "*.mp3"

นี่เป็นเพียงรายการที่ค้นพบหากคุณต้องการลบพวกเขาเพียงแค่ผนวก-deleteตัวเลือกที่ส่วนท้ายของคำสั่ง และเช่นเคยกับการกระทำการลบ: โปรดตรวจสอบอย่างรอบคอบแรก

findman findมีตันของตัวเลือกที่มีประโยชน์เป็นอย่างดีอธิบายได้ด้วย


1
โปรดทราบว่าfindคำสั่งนี้เรียกซ้ำ ( แก้ไข: เหมือนเดิมแสดง - ฉันอาจเก็บความคิดเห็นนี้ไว้สำหรับข้อมูลที่เกี่ยวข้องเพิ่มเติม แต่ไม่จำเป็นที่จะสื่อถึง) เพื่อหาไฟล์ที่พำนักอยู่เพียงในไดเรกทอรีปัจจุบัน แต่ไม่ยังไดเรกทอรีย่อย - และทำให้เพียงลบไฟล์เหล่านั้นถ้า-deleteการดำเนินการจะมีการเพิ่ม - คุณสามารถเพิ่มทันทีหลังจากที่-maxdepth 1 find .สิ่งนี้จะทำให้มันสอดคล้องกับผลกระทบของการทำให้เป็นวงกลมเนื่องจาก globs จะไม่สามารถเรียกคืนได้ใน Bash ยกเว้นว่าglobstarตัวเลือกเชลล์นั้นเปิด**ใช้งานและถูกใช้งาน glob ที่แสดงในคำถามจะไม่เรียกคืนในทุกเชลล์
Eliah Kagan

2
"ไม่มีทาง (ฉันรู้) จะลบล้างพวกเขา" เมื่อใช้shopt -s extglobคุณสามารถใช้echo 1.!(gif|csv|mp3)ซึ่งพิมพ์ทั้งหมด1.extที่extไม่ได้gif, หรือcsv mp3(ดูส่วนย่อยของ "การจับคู่รูปแบบ" man bash)
wchargin

10

ฉันคิดว่าคุณเข้าใจผิดเกี่ยวกับการใช้วงเล็บ [abc]ตรงกับหนึ่งในตัวละครa, หรือb ตรงกับหนึ่งในตัวละครที่เป็นไม่ได้ , หรือ ดังนั้นคำสั่งc[!abc] abc

rm myfile [192]

จะลบmyfileและไฟล์1, 9และ2เพราะคุณมีช่องว่างระหว่าง myfile และยึดที่ ในทางตรงกันข้ามคำสั่ง

rm myfile[192]

จะลบไฟล์myfile1, และmyfile9myfile2


จริง findดีกว่าที่จะใช้
pLumo

ที่จริง [] ใช้สำหรับช่วง [!] อักขระเดียว
IronUhlan

1
@IronUhlan พวกเขาทั้งคู่มีช่วงหรือรายการของอักขระ เป็นเพียงแค่ที่อื่น ๆ คือการปฏิเสธ
ilkkachu

7

วงเล็บ[ ]แสดงถึงคลาสตัวละคร อักขระเดี่ยวใด ๆ ที่อยู่ภายในอาจตรงกันในตำแหน่งที่กำหนด ดังนั้น

file[192]

ตรงกับสามชื่อที่เป็นไปได้:

file1
file2
file9

มันไม่ได้ตรงกับเพราะเพียงเกี่ยวข้องกับตัวเดียวหลังจากที่file192file

เรายังสามารถใช้ช่วงเป็นวงเล็บปีกกา [0-9]ตรงกับตัวเลขใด ๆ ในตำแหน่งที่กำหนด [0-9][0-9]สำหรับตัวเลขสองหลักที่เราต้อง สำหรับหลักตามด้วยตัวพิมพ์ใหญ่เราสามารถใช้[0-9][A-Z]...

! หมายถึงการปฏิเสธ

file[!192]

จะตรงกับแฟ้มที่มีตัวเดียวใด ๆ หลังจากที่fileยกเว้น1หรือหรือ9 2ตัวอย่างเช่นจะจับคู่file7และfilesและfile%(และอื่น ๆ อีกมากมาย) แต่ไม่ใช่ file192เพราะนั่นมีอักขระพิเศษสองตัว

สำหรับกรณีการใช้งานของคุณผมขอแนะนำให้ใช้แทนfind [!]มันมีnotผู้ประกอบการ

นอกจากนี้ยังเรียกซ้ำได้ซึ่งหมายความว่าจะเข้าสู่ไดเรกทอรีย่อยทั้งหมดตามค่าเริ่มต้น คุณสามารถ จำกัด ไว้ที่ไดเรกทอรีปัจจุบันด้วย-maxdepth 1หากนั่นคือสิ่งที่คุณต้องการ Shell wildcards (globbing) นั้นไม่ใช่แบบเรียกซ้ำ (แม้ว่าการวนซ้ำแบบวนซ้ำด้วย**สามารถเปิดใช้งานได้)

สมมติว่าคุณไม่ต้องการหลีกเลี่ยงการลบ symlink เราสามารถเพิ่ม-type dการทดสอบเมื่อตะกี้เพื่อหลีกเลี่ยงการลบไดเรกทอรีใด ๆ ขอบคุณ Eliah Kagan สำหรับคำแนะนำนั้น

find /path -maxdepth 1 -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \)

หากคุณเห็นสิ่งที่คุณต้องการคุณสามารถเรียกใช้คำสั่งอีกครั้งด้วย -delete

find /path -maxdepth 1  -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \) -delete

2
และฉันคิดว่าคุณสามารถทำได้หลายช่วงพร้อมกัน ตัวอย่างเช่นเลขฐานสิบหกอาจเป็นได้[0-9a-fA-F]
Wilson

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