วนซ้ำแบบซ้ำ


80

ฉันต้องการเขียนสิ่งนี้:

$ ls **.py

เพื่อให้ได้ชื่อไฟล์. py ทั้งหมดให้เดินลำดับชั้นไดเรกทอรีซ้ำ

แม้ว่าจะมีไฟล์. py ที่ต้องการค้นหาเชลล์ (bash) จะให้เอาต์พุตนี้:

ls: cannot access **.py: No such file or directory

มีวิธีใดที่จะทำสิ่งที่ฉันต้องการ

แก้ไข:ฉันต้องการระบุว่าฉันไม่สนใจเฉพาะกรณีlsแต่คำถามเกี่ยวกับไวยากรณ์ glob

คำตอบ:


98

ในการที่จะทำซ้ำ globs ใน bash คุณต้องใช้globstarคุณสมบัติจาก bash เวอร์ชัน 4 หรือสูงกว่า

จาก manpage ทุบตี:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

สำหรับรูปแบบตัวอย่างของคุณ:

shopt -s globstar
ls **/*.py

2
ฉันขอแนะนำให้เปิดใช้งานด้วยnullglob
เกล็นแจ็

6
@glennjackman แต่ก่อนที่จะเปิดnullglobผมจะขอแนะนำให้อ่านต่อไปนี้คำเตือน
Serge Stroobandt

2
^ คำเตือนย้ายมาที่นี่แล้ว
usandfriends

1
ด้วย bash 3.2 ใช้wc -l {**,.}/*.pyงานได้ดี
Raphael

@ ราฟาเอลฉันตรวจสอบบันทึกประจำรุ่นอีกครั้งและมันก็บอกว่ามันถูกนำมาใช้ใน 4.0 บางทีการกระจายของคุณมีแพทช์ backported หรือไม่ IIRC RHEL 5 ได้นำคุณสมบัติบางอย่างกลับมา ยังมีโน้ตจะได้รับ 9 ปีนับตั้งแต่ทุบตี 4 ได้รับการปล่อยตัว ...
jordanm

10
find . -name '*.py'

** ไม่ได้ทำอะไรมากกว่าหนึ่ง * ทั้งสองทำงานในไดเรกทอรีปัจจุบัน


น่าสนใจ แม้ว่าฉันจะมุ่งเน้นไปที่ไวยากรณ์แบบหมุนด้วยตัวเองเพราะฉันต้องใช้มันในไฟล์กำหนดค่า (รวมถึงคำสั่ง) ฉันไม่ต้องการรายการไฟล์
เปาโล

2
@Doug O'Neal ไม่จริงอีกต่อไป ทุบตีได้คัดลอกในขณะนี้ว่าคุณลักษณะ zsh (แม้ว่ามันจะนำมาใช้ไวยากรณ์ที่ใกล้ชิดกับที่ของ ksh93 และชอบ ksh ไม่สนับสนุนบ่น globbing zsh ของยังที่ จำกัด ประโยชน์ของมัน)
Stéphane Chazelas

มีหลายสิ่งที่คุณสามารถทำได้ด้วยfindหากคุณไม่มีทุบตี 4. ตัวอย่าง: yourcommand `find . -name '*.py'`(หมายเหตุ backticks); find . -name '*.py' -exec yourcommand {} \;.
ดาวอังคาร

5

เนื่องจาก Bash 4 (รวมถึง zsh) จึงมีการเพิ่มตัวเลือกแบบวงกลมใหม่ ( globstar) ลงไปซึ่งถือว่ารูปแบบ**แตกต่างกันเมื่อตั้งค่า

มันกำลังจับคู่รูปแบบไวด์การ์ดและส่งคืนไฟล์และชื่อไดเรกทอรีที่ตรงกันจากนั้นโดยแทนที่รูปแบบไวด์การ์ดในคำสั่งด้วยรายการที่ตรงกัน

โดยปกติเมื่อคุณใช้**มันจะทำงานคล้ายกับ*แต่มันจะทำซ้ำไดเรกทอรีทั้งหมดซ้ำ (เช่นวนซ้ำ)

หากต้องการดูว่าเปิดใช้งานหรือไม่ให้ตรวจสอบโดยshopt globstar(ในการใช้สคริปต์ใช้shopt -q globstar)

ตัวอย่าง**.pyจะใช้ได้เฉพาะกับไดเรกทอรีปัจจุบันเนื่องจากไม่ส่งคืนรายการของไดเรกทอรีที่สามารถเรียกซ้ำได้ดังนั้นจึงเป็นเหตุผลที่คุณต้องใช้สัญลักษณ์ตัวแทนระดับไดเรกทอรีหลายรายการ**/*.pyเพื่อให้สามารถทำงานได้ลึกขึ้น

โปรดหาการทดสอบไวยากรณ์น้อยมากซึ่งฉันได้ทำการค้นหาไฟล์ทั้งหมดซ้ำ

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