วิธีค้นหาไฟล์ในส่วนย่อยและจัดเรียงตามชื่อไฟล์ในคำสั่งเดียว?


9

ผลการค้นหาปกติที่ใช้find . ! -path "./build*" -name "*.txt":

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

และเมื่อเรียงลำดับด้วยsort -n:

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

อย่างไรก็ตามผลลัพธ์ที่ต้องการคือ:

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

ซึ่งหมายความว่าผลลัพธ์จะถูกจัดเรียงตามชื่อไฟล์เท่านั้นแต่ควรรักษาข้อมูลโฟลเดอร์ไว้เป็นส่วนหนึ่งของผลลัพธ์

แก้ไข : ทำให้ตัวอย่างมีความซับซ้อนมากขึ้นเนื่องจากโครงสร้างไดเรกทอรีย่อยอาจมีมากกว่าหนึ่งระดับ


2
ดูคำถามนี้ผมถามในดังนั้น: stackoverflow.com/questions/3222810/...
camh

@camh - ถ้าเป็นไปได้ฉันต้องการใช้เฉพาะคำสั่ง unix ในกรณีใด ๆ คำถามของฉันจะค่อนข้างซ้ำซ้อนกับคุณ คุณสามารถถ่ายโอนทางออกที่ดีที่สุดไปยังเธรดนี้ (เก็บลิงค์ไปยัง anyways ดั้งเดิม) เพื่อให้ฉันสามารถทำเครื่องหมายว่าเป็นวิธีการแก้ปัญหา?
เปิดทำการ

หาก @Shawn ทำการเปลี่ยนแปลงที่ฉันแนะนำในความคิดเห็นของฉัน (ใช้-printfแทนawk) ฉันคิดว่านั่นเป็นทางออกที่ดีที่สุด ฉันได้ทำใหม่การใช้งานดั้งเดิมของฉันเพื่อใช้วิธีนี้
camh

คำตอบ:


9

คุณต้องเรียงลำดับตามฟิลด์สุดท้าย (พิจารณา/เป็นตัวคั่นฟิลด์) น่าเสียดายที่ฉันไม่สามารถนึกถึงเครื่องมือที่สามารถทำสิ่งนี้ได้เมื่อจำนวนของเขตข้อมูลแตกต่างกันไป (หากทำได้เพียงsort -kค่าลบ)

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

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

awkคำสั่งนั้นบอกว่าตัวคั่นฟิลด์ FSถูกตั้งค่าเป็น/; สิ่งนี้มีผลต่อวิธีการอ่านฟิลด์ คั่นฟิลด์เอาท์พุท OFSตั้งยัง/; สิ่งนี้มีผลต่อวิธีพิมพ์ระเบียน คำสั่งถัดไปบอกว่าพิมพ์คอลัมน์สุดท้าย ( NFคือจำนวนเขตข้อมูลในระเบียนดังนั้นจึงเกิดขึ้นเป็นดัชนีของเขตข้อมูลสุดท้าย) เช่นเดียวกับระเบียนทั้งหมด ( $0เป็นระเบียนทั้งหมด); มันจะพิมพ์พวกเขาด้วย OFS ระหว่างพวกเขา จากนั้นรายการจะได้รับsortการปฏิบัติ/เหมือนเป็นตัวคั่นฟิลด์ - เนื่องจากเรามีชื่อไฟล์แรกในเร็กคอร์ดมันจะเรียงลำดับตามนั้น จากนั้นcutพิมพ์เฉพาะฟิลด์ 2 ถึงจุดสิ้นสุดเท่านั้นถือว่า/เป็นตัวคั่นฟิลด์อีกครั้ง


3
เนื่องจากนี่คือด้วย find (1) คุณสามารถข้ามส่วน awk และใช้งานได้-printf '%f/%p\n'
camh

แน่นอนการตั้งค่าของเรานั้นซับซ้อนกว่าเล็กน้อย มันรวมถึงความลึกของตัวแปรย่อย แก้ไขคำถามเพื่อสะท้อนข้อเท็จจริงนี้ ฉันขอโทษที่ไม่ได้รวมสิ่งนี้ไว้ในตอนแรก
เปิดทำการ

1
@ Unode: วิธีการแก้ปัญหาของ Shawn สามารถจัดการความลึกของตัวแปรได้ดีมันเป็นวิธีการแก้ปัญหาที่ยอมรับได้สำหรับปัญหานี้
Gilles 'หยุดความชั่วร้าย' ใน

4

ฉันจะใช้ไฟล์ '-printf' เพื่อชื่อเอาต์พุตและพา ธ เรียงตามชื่อและตัดชื่อในขั้นตอนสุดท้าย '###' เป็นเพียงเครื่องหมายเพื่อช่วยในการตัด

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

% f พิมพ์ชื่อไฟล์% p ตลอดเส้นทาง

ฉันทำให้คำสั่ง find ง่ายขึ้นเพื่อให้เป็นหนึ่งบรรทัดแน่นอนคุณจะออกจาก! -path "./build*"ส่วนนั้น


3

ใน zsh ≥4.3.10:

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txtตรงกับ*.txtในไดเรกทอรีปัจจุบันและไดเรกทอรีย่อยซ้ำ
  • ~build* ไม่รวมการจับคู่ที่มีข้อความขึ้นต้นด้วยbuild*(เช่น! -path './build*') (คุณต้องการsetopt extended_globก่อน)
  • (oe\''…'\')คือการเรียงลำดับคัดเลือก glob REPLY=…สร้างสตริงที่จะเรียงลำดับจากสตริงที่จะกลับมา
  • ${REPLY:t}คือbasename (“ tail”) ของเส้นทาง

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