"Bul" komutunu kullanarak ilk önce nasıl arama yapabilirim?


17

-depthBirincil findbir derinlik ilk arama yapmak neden olur.

Ancak, varsayılan dizisidir değil bir genişlik öncelikli arama.

Varsayılan sıra, gayri resmi olarak " geri izleme sırasında bunu yapmak yerine ilk karşılaştıklarında düğümleri işleyen önce derinlikli çapraz geçiş" olarak tanımlanabilir .

İlk önce geniş bir aramaya ihtiyacım var. findBu şekilde nasıl davranabilirim?


Aşağıdaki kurulum ile gösterim amacıyla:

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

find aşağıdaki varsayılan davranışa sahiptir:

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

ve -depthşu şekilde çalışır:

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

Ancak, istediğim şu (hayali) seçeneği:

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

Başka bir deyişle , devam etmeden önce belirli bir derinlikte tüm dosyaları / dizinleri işlemem find/ raporlamam gerekiyor .

Bunu nasıl yapabilirim?


İle değil find(en azından sadece ile değil find). Yalnızca dosyaları listelemek mi istiyorsunuz, yoksa diğer primerleri kullanmak mı istiyorsunuz?
Gilles 'SO- kötü olmayı bırak'

@Gilles, aslında bunun ihtiyacım -bfsolmayacağını anladım ... GitLab Wiki'ye dahil etmek için uygun büyük bir GitLab projesine bir dizin oluşturan basit bir senaryom var. Üstbilgileri hiyerarşik olarak dizin adlarına göre yapar. Bu büyük çalışır, koyardı Yukarıdaki örnek dosya yapısında olduğunu hariç deltaaltında charlieyerine ebeveyn altında, alt başlığındaki alphabaşlığındaki.
Wildcard

Başka bir tek şey benim olmasıdır findçıkış edilir alfabetik olarak sıralanmış. Hiçbir fikrim neden ....
Wildcard

Yine de, bu kullanım senaryosuna tam olarak uymasa bile kullanışlı -bfs olabileceğini düşünüyorum .
Wildcard

2
Böyle bir araç uyguladım: bfs . GNU find ile henüz% 100 özellik uyumlu değil, ancak oraya varıyor.
Tavian Barnes

Yanıtlar:


6

Bunu sadece kabuk jokerleriyle yapabilirsiniz. Giderek daha fazla dizin seviyesine sahip bir model oluşturun.

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

Bu nokta dosyalarını özlüyor. Kullanım FIGNORE='.?(.)', ksh shopt -s dotglobbash veya setopt glob_dotszsh bunları dahil etmek.

Uyarılar:

  • Bu, çok fazla dosya varsa belleği patlatacaktır.
  • Bu, dizinlere sembolik bağlantıları tekrar tekrar geçirir.

Siparişi veya dizinleri ve dizin olmayanları seçmek istiyorsanız ve performans kritik değilse, iki geçiş yapabilir ve [ -d "$file" ]her geçişte test yapabilirsiniz .


@Wildcard Evet, yaptım.
Gilles 'SO- kötü olmayı bırak'

1
Güzel! Neredeyse önemsiz bir uyarı: Dosya tam anlamıyla adlandırılmışsa, bir dizindeki yalnız dosya olan bir dosyayı işlemeyecektir *. :)
Wildcard

@Wildcard Oh, evet, bundan bahsetmeyi unuttum. Bu kenardan kaçınmak için bash veya zsh tuşlarını kullanın nullglobve (($#))döngü koşulu olarak kullanın.
Gilles 'SO- kötü olmayı bırak'

5

# cat ./bfind

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

Bu, derinliğini arttırarak findve tekrarlayarak çalışır, bence sonuçları tekrarlayabilir, ancak kolayca filtrelenebilir


Üzgünüm, biçimlendirme mekanizması hakkında bir bilgim yoktu. Her neyse, aslında tekrarlamıyor sanırım çünkü mindepth'den daha az bir şey kesiyor
user239175

3

Sen boru kutunu findbir tür içine öncelikle sayısına göre sıralar /yol adında karakterler. Örneğin,

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

Bu awk, yol adını eğik çizgi sayısı ile önek olarak kullanır sedve sonunda bu öneki kaldırır.

Aslında, muhtemelen dizinin içeriğinin alpha/charlie+daha sonra listelenmesini istediğiniz için, istediğiniz derinliğe kadar alpha/charliesöylemeniz gerekir sort -t/ -k1,1 -k2,2 -k3,3 -k4,4.


0

'Find' değil bash temelli başka bir yanıt - önce "üst dizinin uzunluğunu" kullanın, sonra alfaya göre sıralayın.

Sonuçlarınız "charlie, bravo, delta" olduğu için cevap tam olarak eşleşmiyor ama alfa sırayla "bravo, charlie, delta" olup olmadığını merak ettim.

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

Üreten

  $ 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.