รายการไดเรกทอรีย่อยเพียงระดับลึก


58

เทศกาลจัดเก็บข้อมูล voicepack ในโครงสร้างไดเรกทอรีตัวอย่างต่อไปนี้:

/usr/share/festival/voices/<language>/<voicepack name>

หนึ่งซับที่ง่ายที่สุด (ควรใช้ls) ในการพิมพ์เฉพาะ<voicepack name>ในทุก<language>ไดเรกทอรีย่อยที่อาจเกิดขึ้นคืออะไร?

คำตอบ:


80

ฉันอยู่ที่ Fedora และชุดเสียงเหล่านี้อยู่ในตำแหน่งที่แตกต่างกันเล็กน้อย:

$ ls /usr/share/festival/lib/voices/*/ -1 | grep -vE "/usr|^$"
kal_diphone
ked_diphone
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_rms_arctic_hts
nitech_us_slt_arctic_hts

คุณสามารถแก้ไขได้ดังนี้:

$ ls /usr/share/festival/voices/*/ -1 | grep -vE "/usr|^$"

ใช้การค้นหา

การใช้lsในคฤหาสน์นี้มักจะขมวดคิ้วเนื่องจากผลลัพธ์ของlsการแยกวิเคราะห์ยาก ดีกว่าที่จะใช้findคำสั่งเช่น:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -exec basename {} \;
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_slt_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_rms_arctic_hts
ked_diphone
kal_diphone

รายละเอียดของ find & basename

คำสั่งนี้ทำงานโดยสร้างรายการพา ธ แบบเต็มไปยังไฟล์ที่มีความลึก 2 ระดับอย่างแท้จริงเมื่อเทียบกับไดเร็กทอรีนี้:

/usr/share/festival/lib/voices

รายการนี้มีลักษณะดังนี้:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 
/usr/share/festival/lib/voices/us/nitech_us_awb_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_bdl_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_slt_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_jmk_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_clb_arctic_hts
/usr/share/festival/lib/voices/us/nitech_us_rms_arctic_hts
/usr/share/festival/lib/voices/english/ked_diphone
/usr/share/festival/lib/voices/english/kal_diphon

แต่เราต้องการส่วนสุดท้ายของไดเรกทอรีเหล่านี้คือโหนดใบไม้ ดังนั้นเราสามารถใช้ประโยชน์ในbasenameการแยกวิเคราะห์:

$ basename /usr/share/festival/lib/voices/us/nitech_us_awb_arctic_hts
nitech_us_awb_arctic_hts

เมื่อรวมทั้งหมดเข้าด้วยกันเราสามารถทำให้findคำสั่งส่งแต่ละไดเร็กทอรีระดับลึกไปยังbasenameคำสั่ง สัญกรณ์basename {}คือสิ่งที่กำลังทำการแปลงชื่อฐานเหล่านี้ ค้นหาการโทรผ่าน-execสวิตช์


ฮ่า ๆ สวยมากว่าคำตอบเดียวกันจิตใจที่ดีและสิ่งที่ :)
terdon

+1 - สำหรับผู้ที่สะดุดเมื่อรู้ว่ามีอะไร-exec basename {}คุณช่วยอธิบายที่นี่ได้ไหม
user66001

@ user66001 - แจ้งให้เราทราบหากอธิบายได้เพียงพอหรือไม่
slm

@ user66001 - คุณสามารถยอมรับหนึ่งในคำตอบถ้ามันแก้ปัญหาของคุณเพื่อความพึงพอใจของคุณ 8-)
slm

1
คำสั่ง find คือสิ่งที่ฉันต้องการ 99% ของเวลา จำกัด ทั้งค่าสูงสุดและค่าต่ำสุดคือกุญแจ - ฉันทำได้แค่สูงสุด ตัวอย่าง: find ~/ -maxdepth 1 -mindepth 1 -type d | xargs du -csh | sort -h ค้นหาไดเรกทอรีที่ใหญ่ที่สุดเรียงตามขนาด
oligofren

23

วิธีที่ง่ายที่สุดคือ

ls -d /usr/share/festival/voices/*/*

ที่ถูกขยายโดยเชลล์ลงในไดเรกทอรีย่อยทั้งหมด/usr/share/festival/voices/แล้วไปยังเนื้อหาของแต่ละไดเรกทอรีย่อยเหล่านั้น

หากคุณต้องการลงไปสู่ระดับเฉพาะตามที่ชื่อของคุณแนะนำด้วยการใช้งานfindเช่น GNU และ BSD บางส่วน:

find /usr/share/festival/voices/ -mindepth 2 -maxdepth 3 -type d

ที่จะค้นหาไดเรกทอรีทั้งหมด ( -type d) ที่อยู่ในไดเรกทอรีย่อย/usr/share/festival/voices/เนื่องจากmindepth 2แต่ไม่ลึกกว่า 3 ระดับลง ( maxdepth 3) จากman find:

   -maxdepth levels
          Descend at most levels (a non-negative integer) levels of direc
          tories below the command line arguments.  -maxdepth 0
           means only apply the tests and  actions  to  the  command  line
          arguments.

   -mindepth levels
          Do  not apply any tests or actions at levels less than levels (a
          non-negative integer).  -mindepth  1  means  process  all  files
          except the command line arguments.

ใช่มันเหมือนกับการมองในกระจก 8-)
slm

+1 วิธีที่คุณทั้งสองได้รับ 2 คะแนนน่าสนใจ การลงคะแนนไขว้อธิบายแต่ละข้อ 1) PS ฉันต้องการชื่อไดเรกทอรีดังนั้นเพียงเปลี่ยน-type fเป็น-type dควรแก้ไขปัญหานี้ใช่ไหม จะรอการตอบสนองของ slm เกี่ยวกับจุดประสงค์ของ-exec basename {}
user66001

@ user66001 ใช่-type dจะพบไดเรกทอรี basenameเป็นความคิดที่ดีมากก็จะพิมพ์เฉพาะชื่อและลบเส้นทาง สมมติว่าคุณต้องการแค่ชื่อนั่นคือสิ่งที่คุณควรทำ ได้ดูและยังman basename man dirname
terdon

ขอบคุณ terdon - ขออภัยที่ไม่ทำเครื่องหมายคำตอบของคุณ รู้สึกว่ารุ่นปัจจุบันของ SLM 'sมีข้อมูลเพิ่มเติมสำหรับผู้ที่จำเป็นต้องใช้มัน
user66001

1
@ user66001 ก่อนอื่นคุณพูดถูก slm ดีกว่าจริงๆ ประการที่สองคุณไม่ควรขอโทษที่ไม่ยอมรับมีเพียงคนเดียวเท่านั้นและนั่นควรจะเป็นสิ่งที่คุณคิดว่าดีที่สุด :)
terdon

6

ตอบรับทำงานอย่างถูกต้อง แต่อาจจะไม่มีประสิทธิภาพเพราะมัน spawns ใหม่basenameกระบวนการสำหรับแต่ละไดเรกทอรีย่อย:

find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -exec basename {} \;

เมื่อเป็นไปได้ควรใช้คุณลักษณะที่มีในตัวfindเพื่อหลีกเลี่ยงค่าใช้จ่ายของกระบวนการวางไข่ findมีความสามารถที่กว้างขวางพอสมควรในการปรับเปลี่ยนผลงานพิมพ์โดยใช้-printfแอ็คชัน การ-print ดำเนินการเริ่มต้นพิมพ์เส้นทางทั้งหมด แต่ใช้-printfและสตริงรูปแบบเป็นไปได้ที่จะเลือกส่วนของเส้นทางสำหรับการพิมพ์ เพื่อดึงเพียงส่วนชื่อไฟล์ของเส้นทางที่ไม่มีไดเรกทอรีชั้นนำ (ในขณะที่basename ไม่) %fสตริงรูปแบบคือ หากต้องการวางบรรทัดใหม่หลังชื่อไฟล์แต่ละรายการให้รวม\nดังนี้:

$ find /usr/share/festival/lib/voices -maxdepth 2 -mindepth 2 \
    -type d -printf '%f\n'
nitech_us_awb_arctic_hts
nitech_us_bdl_arctic_hts
nitech_us_slt_arctic_hts
nitech_us_jmk_arctic_hts
nitech_us_clb_arctic_hts
nitech_us_rms_arctic_hts
ked_diphone
kal_diphone

+1 ขอบคุณสำหรับคำตอบของคุณ Michael ฉันเห็นข้อดีของวิธีการทำเช่นนี้ในคำตอบของคุณ แต่ให้งานเขียนเป็นคำตอบของ slmฉันอยู่ที่ใจสองคนเกี่ยวกับการเปลี่ยนคำตอบที่ยอมรับ หาก @slm เห็นสิ่งนี้และไม่มีปัญหาในการเลือกสิ่งนี้กับเขาฉันจะกลับมาที่นี่เพื่อเปลี่ยนคำตอบที่ยอมรับ
user66001

1
คำตอบของ @ slm ได้รับการอธิบายอย่างดีและครอบคลุมรูปแบบการใช้งานทั่วไปที่กว้างขึ้นfindด้วยคำสั่งภายนอกโดยพลการ มันมีประสิทธิภาพน้อยกว่าสำหรับการทำงานที่ติดตั้งไว้findภายใน ฉันได้พิจารณาเพิ่มความคิดเห็นในคำตอบของเขา แต่นั่นต้องมีชื่อเสียงมากกว่าที่ฉันมี ไม่จำเป็นต้องเปลี่ยนคำตอบที่คุณยอมรับเนื่องจากคำตอบที่ยอมรับในปัจจุบันนั้นถูกต้องอธิบายได้ดีและใช้เป็นรูปแบบสำหรับกรณีทั่วไปได้มากขึ้น ฉันแค่อยากจะชี้ให้เห็นว่าสำหรับกรณีนี้มีวิธีที่มีประสิทธิภาพมากกว่า
Michael Henry

0

TLDR; สำหรับผู้ที่เพิ่งมาที่นี่ตามชื่อของคำถามนี้ ถึง "แสดงรายการไดเรกทอรีย่อยเฉพาะระดับ n ลึก": ใช้

find -maxdepth N

อยู่ที่ไหนNหมายเลขใด

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