ฉันรู้ว่า**/*.ext
ขยายไปยังไฟล์ทั้งหมดในไดเร็กทอรีย่อยทั้งหมดที่ตรงกัน*.ext
แต่ส่วนขยายที่คล้ายกันที่รวมไฟล์ดังกล่าวทั้งหมดในไดเร็กทอรีปัจจุบันด้วยคืออะไร
globstar
ตัวเลือกตามคำตอบของเดนนิส
ฉันรู้ว่า**/*.ext
ขยายไปยังไฟล์ทั้งหมดในไดเร็กทอรีย่อยทั้งหมดที่ตรงกัน*.ext
แต่ส่วนขยายที่คล้ายกันที่รวมไฟล์ดังกล่าวทั้งหมดในไดเร็กทอรีปัจจุบันด้วยคืออะไร
globstar
ตัวเลือกตามคำตอบของเดนนิส
คำตอบ:
สิ่งนี้จะใช้ได้ใน Bash 4:
ls -l {,**/}*.ext
เพื่อให้ลูกโลกเครื่องหมายดอกจันคู่ทำงานได้globstar
จำเป็นต้องตั้งค่าตัวเลือก (ค่าเริ่มต้น: เปิด):
shopt -s globstar
จากman bash
:
globstar หากตั้งค่ารูปแบบ ** จะใช้ในการขยายชื่อไฟล์ตาม ข้อความจะตรงกับไฟล์และไดเร็กทอรีศูนย์หรือมากกว่าและ ไดเรกทอรีย่อย ถ้ารูปแบบตามด้วย / ให้เท่านั้น ไดเรกทอรีและไดเรกทอรีย่อยตรงกัน
ตอนนี้ฉันกำลังสงสัยว่าครั้งหนึ่งอาจมีข้อผิดพลาดในการประมวลผลของ globstar หรือไม่เพราะตอนนี้ใช้เพียงแค่ls **/*.ext
ฉันได้ผลลัพธ์ที่ถูกต้อง
ไม่ว่าฉันจะดูที่การวิเคราะห์ kenorb โดยใช้ที่เก็บ VLC และพบปัญหาบางอย่างกับการวิเคราะห์นั้นและในคำตอบของฉันด้านบนทันที:
การเปรียบเทียบกับเอาต์พุตของfind
คำสั่งนั้นไม่ถูกต้องเนื่องจากการระบุ-type f
ไม่รวมไฟล์ประเภทอื่น ๆ (โดยเฉพาะไดเร็กทอรี) และls
คำสั่งที่อยู่ในรายการอาจเป็นไปได้ นอกจากนี้หนึ่งในคำสั่งที่อยู่ในรายการls -1 {,**/}*.*
ซึ่งดูเหมือนจะขึ้นอยู่กับของฉันด้านบนจะแสดงเฉพาะชื่อที่มีจุดสำหรับไฟล์ที่อยู่ในไดเรกทอรีย่อย คำถามของ OP และคำตอบของฉันมีจุดเนื่องจากสิ่งที่กำลังค้นหาคือไฟล์ที่มีนามสกุลเฉพาะ
ที่สำคัญที่สุดก็คือว่ามีปัญหาพิเศษโดยใช้คำสั่งที่มีรูปแบบls
GLOBSTAR **
รายการที่ซ้ำกันจำนวนมากเกิดขึ้นเนื่องจากรูปแบบถูกขยายโดย Bash ไปยังชื่อไฟล์ทั้งหมด (และชื่อไดเร็กทอรี) ในโครงสร้างที่กำลังตรวจสอบ หลังจากการขยายls
คำสั่งจะแสดงรายการแต่ละรายการและเนื้อหาหากเป็นไดเร็กทอรี
ตัวอย่าง:
ในไดเร็กทอรีปัจจุบันของเราคือไดเร็กทอรีย่อยA
และเนื้อหา:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
ในแผนภูมิ**
ขยายเป็น "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 รายการ) . หากคุณทำecho **
นั่นคือผลลัพธ์ที่แน่นอนที่คุณจะได้รับและแต่ละรายการจะแสดงครั้งเดียว อย่างไรก็ตามหากคุณทำls **
มันจะแสดงรายการของแต่ละรายการเหล่านั้น โดยพื้นฐานแล้วจะls A
ตามด้วยls A/AB
ฯลฯ ดังนั้นจึงA/AB
แสดงสองครั้ง นอกจากนี้ls
กำลังจะแยกเอาต์พุตของไดเรกทอรีย่อยแต่ละรายการออกจากกัน:
...
<blank line>
directory name:
content-item
content-item
ดังนั้นการใช้การwc -l
นับบรรทัดว่างเหล่านั้นและส่วนหัวของชื่อไดเร็กทอรีทั้งหมดซึ่งจะทำให้การนับห่างออกไป
นี้เลยเหตุผลที่คุณไม่ควรอีกแยกls
จากการวิเคราะห์เพิ่มเติมนี้ฉันไม่แนะนำให้ใช้รูปแบบ globstar ในกรณีใด ๆ นอกเหนือจากการวนซ้ำบนต้นไม้ของไฟล์ในลักษณะนี้:
for entry in **
do
something "$entry"
done
ในการเปรียบเทียบขั้นสุดท้ายฉันใช้ที่เก็บซอร์ส Bash ที่ฉันมีสะดวกและทำสิ่งนี้:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
ฉันเคยtr
เปลี่ยนช่องว่างเป็นขึ้นบรรทัดใหม่ซึ่งใช้ได้เฉพาะที่นี่เนื่องจากไม่มีการเว้นวรรคชื่อ ฉันเคยsed
ลบชั้นนำ./
ออกจากแต่ละบรรทัดของเอาต์พุตจากfind
. ฉันเรียงลำดับผลลัพธ์find
เนื่องจากโดยปกติจะไม่มีการเรียงลำดับและการขยายตัวของ Bash นั้นถูกจัดเรียงเรียบร้อยแล้ว ในขณะที่คุณสามารถดูการส่งออกเพียงอย่างเดียวจากdiff
เป็นไดเรกทอรีปัจจุบันเอาท์พุท.
find
เมื่อฉันทำls ** | wc -l
เอาต์พุตมีจำนวนบรรทัดเกือบสองเท่า
globstar
เป็นค่าเริ่มต้นoff
**/*.ext
น่าจะเพียงพอแล้ว shopt -s dotglob
นอกจากนี้คุณจะไม่ได้มีไฟล์ที่ซ่อนอยู่เว้นแต่คุณ
globstar
: shopt -u globstar
.
**/*.ext
ไม่เพียงพอ
สิ่งนี้จะพิมพ์ไฟล์ทั้งหมดในไดเร็กทอรีปัจจุบันและไดเร็กทอรีย่อยซึ่งลงท้ายด้วย ".ext"
find . -name '*.ext' -print
คุณสามารถใช้: **/*.*
จะรวมไฟล์ทั้งหมดซ้ำ (เปิดใช้งานโดย: shopt -s globstar
)
โปรดดูการทดสอบรูปแบบอื่น ๆ ด้านล่างและวิธีการทำงาน
การทดสอบโฟลเดอร์ที่มีไฟล์ 3472 ในโฟลเดอร์ที่เก็บVLCตัวอย่าง:
(ไฟล์ของ 3472 นับเป็นต่อทั้งหมด: find . -type f | wc -l
)
ls -1 **/*.*
- ส่งคืน 3338ls -1 {,**/}*.*
- ส่งคืน 3341 (ตามที่เสนอโดยDennis )ls -1 {,**/}*
- ส่งคืน 8265ls -1 **/*
- ส่งคืน 7817 ยกเว้นไฟล์ที่ซ่อนอยู่ (ตามที่เสนอโดยDennis )ls -1 **/{.[^.],}*
- ส่งคืน 7869 (ตามที่เดนนิสเสนอ)ls -1 {,**/}.?*
- ส่งคืน 15855ls -1 {,**/}.*
- ส่งคืน 20321ดังนั้นฉันคิดว่าวิธีที่ใกล้เคียงที่สุดในการแสดงรายการไฟล์ทั้งหมดแบบวนซ้ำคือตัวอย่างแรก ( **/*.*
) ตามความคิดเห็นของ gniourf-gniourf (สมมติว่าไฟล์มีนามสกุลที่เหมาะสมหรือใช้ไฟล์ที่เฉพาะเจาะจง) เนื่องจากตัวอย่างที่สองมีรายการที่ซ้ำกันน้อยกว่าดังต่อไปนี้ :
$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63 2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62 2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
COPYING.LIB
-COPYING.LIB
-Makefile.am
Makefile.am
@@ -45,7 +43,6 @@
compat/tdestroy.c
compat/vasprintf.c
configure.ac
-configure.ac
และอีกรายสร้างรายการซ้ำเพิ่มเติม
ในการรวมไฟล์ที่ซ่อนไว้ให้ใช้: shopt -s dotglob
(ปิดการใช้งานโดยshopt -u dotglob
) ไม่แนะนำเนื่องจากอาจส่งผลต่อคำสั่งเช่นmv
หรือrm
และคุณสามารถลบไฟล์ที่ไม่ถูกต้องโดยไม่ตั้งใจ
**/*.*
) ให้ข้อมูลและทำงานได้ดีที่สุด คำตอบที่ยอมรับทำให้เกิดรายการที่ซ้ำกันในไดเรกทอรีด้านบน รูปแบบการทำงานของฉันคือ:"${path}"**/*.*
$ find . -type f
ซึ่งจะแสดงรายการไฟล์ทั้งหมดในไดเร็กทอรีปัจจุบัน จากนั้นคุณสามารถทำคำสั่งอื่น ๆ กับเอาต์พุตโดยใช้ -exec
$find . -type f -exec grep "foo" {} \;
ซึ่งจะ grep แต่ละไฟล์จากการค้นหาสำหรับสตริง "foo"
find . -type f
ใช้ซ้ำกับ root ที่ไดเร็กทอรีปัจจุบันไม่ใช่เฉพาะกับไดเร็กทอรีปัจจุบัน
ทำไมไม่ใช้เพียงแค่ขยายวงเล็บปีกกาเพื่อรวมไดเรกทอรีปัจจุบันด้วย
./{*,**/*}.ext
การขยายตัวของ Brace เกิดขึ้นก่อนการขยายแบบ glob ดังนั้นคุณสามารถทำสิ่งที่คุณต้องการได้อย่างมีประสิทธิภาพด้วย bash เวอร์ชันเก่าและสามารถละทิ้งการใช้ globstar ในเวอร์ชันใหม่
นอกจากนี้ยังถือเป็นแนวทางปฏิบัติที่ดีในการทุบตีเพื่อรวมความเป็นผู้นำ./
ในรูปแบบลูกโลกของคุณ
**/*.ext
ทุบตีฉันไม่ได้จัดการ คุณแน่ใจหรือไม่ว่าจะได้ผลสำหรับคุณ