ฉันจะค้นหาแบบกว้างโดยใช้ 'find' ได้อย่างไร


17

-depthหลักในการfindทำให้เกิดการดำเนินการค้นหาความลึกแรก

อย่างไรก็ตามลำดับเริ่มต้นไม่ใช่การค้นหาแบบกว้าง

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

ฉันมีความต้องการที่แท้จริงสำหรับการค้นหาแบบกว้างครั้งแรก ฉันจะfindประพฤติตนในลักษณะนี้ได้อย่างไร


สำหรับภาพประกอบด้วยการตั้งค่าต่อไปนี้:

$ mkdir -p alpha/{bravo,charlie,delta}
$ touch alpha/charlie/{alpha,beta,gamma,phi}

find มีพฤติกรรมเริ่มต้นต่อไปนี้:

$ find alpha
alpha
alpha/charlie
alpha/charlie/alpha
alpha/charlie/phi
alpha/charlie/beta
alpha/charlie/gamma
alpha/delta
alpha/bravo

และด้วย-depthจะดำเนินการดังนี้:

$ find alpha -depth
alpha/charlie/alpha
alpha/charlie/phi
alpha/charlie/beta
alpha/charlie/gamma
alpha/charlie
alpha/delta
alpha/bravo
alpha

อย่างไรก็ตามสิ่งที่ฉันต้องการคือตัวเลือก (สมมติ) ต่อไปนี้:

$ find alpha -bfs
alpha
alpha/charlie
alpha/delta
alpha/bravo
alpha/charlie/alpha
alpha/charlie/phi
alpha/charlie/beta
alpha/charlie/gamma

กล่าวอีกนัยหนึ่งฉันต้องfindดำเนินการ / รายงานไฟล์ทั้งหมด / dirs ที่ระดับความลึกที่กำหนดก่อนที่จะดำเนินการต่อไป

ฉันจะทำสิ่งนี้ได้อย่างไร


ไม่ได้อยู่กับfind(อย่างน้อยไม่ใช่กับเท่านั้นfind) คุณต้องการแสดงรายการไฟล์เท่านั้นหรือคุณต้องการใช้เครื่องมืออื่น ๆ
Gilles 'หยุดความชั่วร้าย'

@Gilles จริงๆแล้วฉันรู้ว่า-bfsคงไม่เป็นอย่างที่ฉันต้องการ ... ฉันมีสคริปต์ง่าย ๆ ที่สร้างดัชนีให้กับโครงการ GitLab ขนาดใหญ่เหมาะสำหรับการรวมไว้ใน GitLab Wiki มันทำให้ส่วนหัวตามลำดับชั้นตามชื่อไดเรกทอรี มันใช้งานได้ดียกเว้นว่าในโครงสร้างไฟล์ตัวอย่างด้านบนมันจะวางไว้deltaใต้หัวเรื่องย่อยcharlieแทนที่จะเป็นใต้alphaหัวเรื่องหลัก
Wildcard

อีกสิ่งที่แปลกก็คือว่าฉันfindเอาท์พุทจะเรียงตามตัวอักษร ไม่รู้เลยว่าทำไม ....
ไวด์การ์ด

ยังฉันคิดว่า-bfs จะมีประโยชน์แม้ว่ามันจะไม่เหมาะกับกรณีการใช้งานนี้
Wildcard

2
ผมนำมาใช้เครื่องมือเช่น: BFS ยังใช้งานไม่ได้กับคุณสมบัติ 100% ของ GNU แต่ยังไปถึงได้
Tavian Barnes

คำตอบ:


6

คุณสามารถทำได้ด้วยการใช้สัญลักษณ์แทนเชลล์ สร้างรูปแบบที่มีระดับไดเรกทอรีมากขึ้นเรื่อย ๆ

pattern='*'
set -- $pattern
while [ $# -ne 1 ] || [ "$1" != "$pattern" ]; do
  for file; do
    …
  done
  pattern="$pattern/*"
  set -- $pattern
done

นี่เป็นจุดที่คิดถึงไฟล์ ใช้FIGNORE='.?(.)'ใน ksh shopt -s dotglobในทุบตีหรือsetopt glob_dotsใน zsh เพื่อรวมพวกเขา

คำเตือน:

  • จะเป็นการเพิ่มหน่วยความจำหากมีไฟล์จำนวนมาก
  • traverses ลิงก์สัญลักษณ์ไปยังไดเรกทอรีแบบเรียกซ้ำ

หากคุณต้องการเลือกลำดับหรือไดเรกทอรีและไม่ใช่ไดเรกทอรีและประสิทธิภาพไม่สำคัญคุณสามารถทำการส่งผ่านสองครั้งและทดสอบ[ -d "$file" ]ในแต่ละรอบได้


@ Wildcard ใช่ฉันทำ
Gilles 'หยุดความชั่วร้าย'

1
ดี! หนึ่งข้อแม้มากขึ้นเล็กน้อยเกือบ: *มันจะล้มเหลวในการประมวลผลไฟล์ที่เป็นไฟล์เดียวในไดเรกทอรีถ้าไฟล์เป็นชื่ออักษร :)
สัญลักษณ์แทน

@ Wildcard โอ้ใช่ฉันลืมที่จะพูดถึงเรื่องนั้น ใช้ bash หรือ zsh ด้วยnullglobและใช้(($#))เป็นเงื่อนไขวงเพื่อหลีกเลี่ยงกรณีขอบนี้
Gilles 'หยุดความชั่วร้าย'

5

# cat ./bfind

#!/bin/bash
i=0
while results=$(find "$@" -mindepth $i -maxdepth $i) && [[ -n $results ]]; do
  echo "$results"
  ((i++))
done

สิ่งนี้ทำงานได้โดยการเพิ่มความลึกfindและการทำซ้ำฉันคิดว่ามันอาจให้ผลลัพธ์ซ้ำ แต่สามารถกรองได้ง่าย


ขออภัยฉันไม่ทราบเกี่ยวกับกลไกการจัดรูปแบบ อย่างไรก็ตามจริงๆแล้วมันไม่ได้ทำซ้ำฉันคิดว่าเพราะมันตัดสิ่งที่น้อยกว่าใจ
user239175

3

คุณสามารถไพพ์ของคุณfindลงในการเรียงลำดับที่เรียงตามหลักของจำนวน/อักขระในชื่อพา ธ ตัวอย่างเช่น,

find alpha |
awk '{n=gsub("/","/",$0);printf "%04d/%s\n",n,$0}' |
sort -t/ |
sed 's|[^/]*/||'

สิ่งนี้ใช้awkเพื่อนำหน้าชื่อพา ธ ที่มีจำนวนสแลชและsedเพื่อลบคำนำหน้านี้ในตอนท้าย

ที่จริงแล้วคุณอาจต้องการให้แสดงเนื้อหาของสารบบalpha/charlie+ในรายการหลังจากalpha/charlieนั้นคุณจะต้องพูดsort -t/ -k1,1 -k2,2 -k3,3 -k4,4ถึงความลึกที่ต้องการ


0

คำตอบอื่น ๆ ไม่ได้ขึ้นอยู่กับ 'find' แต่ใช้ bash - ใช้ "ความยาวของพาเรนต์ไดเร็กทอรี" ก่อนจากนั้นเรียงลำดับตามอัลฟา

คำตอบนั้นไม่ตรงกับผลลัพธ์ของคุณมี "charlie, bravo, delta" แต่ฉันสงสัยว่าควรจะเป็น "bravo, charlie, delta" ตามลำดับอัลฟา

paths_breadth_first() {
  while IFS= read -r line; do
    dirn=${line%/*}         ## dirname(line)
    echo ${#dirn},$line     ## len(dirn),line
  done | sort -n | cut -d ',' -f 2-
}

ที่ผลิต

  $ cat /tmp/yy | paths_breadth_first 
  alpha
  alpha/bravo
  alpha/charlie
  alpha/delta
  alpha/charlie/alpha
  alpha/charlie/beta
  alpha/charlie/gamma
  alpha/charlie/phi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.