Làm cách nào tôi có thể thực hiện tìm kiếm đầu tiên bằng cách sử dụng `find`?


16

Nguyên nhân -depthchính findkhiến nó thực hiện tìm kiếm theo chiều sâu.

Tuy nhiên, chuỗi mặc định không phải là tìm kiếm đầu tiên.

Trình tự mặc định có thể được mô tả không chính thức như là một "giao dịch theo chiều sâu xử lý các nút khi chúng gặp lần đầu thay vì làm như vậy trong quá trình quay lui."

Tôi có một nhu cầu thực sự cho chiều rộng tìm kiếm đầu tiên. Làm thế nào tôi có thể findcư xử theo cách này?


Để minh họa, với các thiết lập sau:

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

find có hành vi mặc định sau:

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

và với -depth, nó thực hiện như sau:

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

Tuy nhiên, điều tôi muốn là tùy chọn (hư cấu) sau:

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

Nói cách khác, tôi cần findxử lý / báo cáo về tất cả các tệp / thư mục ở độ sâu nhất định trước khi tiếp tục.

Tôi có thể làm cái này như thế nào?


Không phải với find(ít nhất, không chỉ với find). Bạn có muốn chỉ liệt kê các tập tin, hoặc bạn muốn sử dụng các bầu cử sơ bộ khác?
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles, thực sự tôi nhận ra rằng đó -bfssẽ không phải là thứ tôi cần ... Tôi có một tập lệnh đơn giản tạo ra một chỉ mục cho một dự án GitLab lớn, phù hợp để đưa vào GitLab Wiki. Nó làm cho các tiêu đề phân cấp dựa trên tên thư mục. Nó hoạt động rất tốt, ngoại trừ trong cấu trúc tệp ví dụ ở trên, nó sẽ đặt deltadưới tiêu đề charliephụ, thay vì dưới alphatiêu đề chính.
tự đại diện

Một điều kỳ lạ nữa là findđầu ra của tôi được sắp xếp theo thứ tự abc. Không biết tại sao ....
Wildcard

Tuy nhiên, tôi nghĩ rằng -bfs có thể có ích, ngay cả khi nó không hoàn toàn phù hợp với trường hợp sử dụng này.
tự đại diện

2
Tôi đã thực hiện một công cụ như vậy: bfs . Nó không tương thích 100% với tính năng tìm thấy GNU, nhưng nó đang ở đó.
Tavian Barnes

Câu trả lời:


6

Bạn có thể làm điều đó chỉ với các ký tự đại diện. Xây dựng một mô hình với các cấp thư mục ngày càng nhiều hơn.

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

Điều này bỏ lỡ các tập tin dấu chấm. Sử dụng FIGNORE='.?(.)'trong ksh, shopt -s dotglobbash hoặc setopt glob_dotszsh để bao gồm chúng.

Hãy cẩn thận:

  • Điều này sẽ làm nổ bộ nhớ nếu có rất nhiều tập tin.
  • Điều này đi qua các liên kết tượng trưng đến các thư mục đệ quy.

Nếu bạn muốn chọn thứ tự hoặc thư mục và không phải thư mục, và hiệu suất không quan trọng, bạn có thể thực hiện hai lần và kiểm tra [ -d "$file" ]trên mỗi lượt.


@Wildcard Vâng, tôi đã làm.
Gilles 'SO- ngừng trở nên xấu xa'

1
Đẹp! Thêm một cảnh báo gần như tầm thường: Sẽ không xử lý tệp là tệp đơn độc trong thư mục nếu tệp được đặt tên theo nghĩa đen *. :)
tự đại diện

@Wildcard Ồ, vâng, tôi quên đề cập đến điều đó. Sử dụng bash hoặc zsh với nullglobvà sử dụng (($#))làm điều kiện vòng lặp để tránh trường hợp cạnh này.
Gilles 'SO- ngừng trở nên xấu xa'

5

# cat ./bfind

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

Điều này hoạt động bằng cách tăng độ sâu findvà lặp lại, tôi nghĩ rằng nó có thể lặp lại kết quả, nhưng có thể được lọc dễ dàng


Xin lỗi tôi không biết về cơ chế định dạng. Dù sao, thực sự nó không lặp lại tôi nghĩ bởi vì nó cắt đứt mọi thứ ít hơn so với mindepth
user239175

3

Bạn có thể findsắp xếp thành một loại sắp xếp chủ yếu theo số lượng /ký tự trong tên đường dẫn. Ví dụ,

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

Điều này sử dụng awkđể tiền tố tên đường dẫn với số lượng dấu gạch chéo và sedđể loại bỏ tiền tố này ở cuối.

Trên thực tế, như bạn có thể muốn nội dung của thư alpha/charlie+mục được liệt kê sau alpha/charlie, bạn cần nói sort -t/ -k1,1 -k2,2 -k3,3 -k4,4đến độ sâu mong muốn.


0

Một câu trả lời khác không dựa trên 'find' mà trên bash - trước tiên hãy sử dụng "độ dài của thư mục mẹ", sau đó sắp xếp theo alpha.

Câu trả lời không hoàn toàn khớp vì kết quả của bạn có "charlie, bravo, delta" nhưng tôi tự hỏi liệu nó có phải là "bravo, charlie, delta" theo thứ tự alpha không.

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-
}

Điều đó tạo ra

  $ 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.