Como posso fazer uma pesquisa inicial usando 'find'?

8

O -depth primary para find faz com que ele realize uma pesquisa em profundidade.

No entanto, a sequência padrão é não uma pesquisa por extensão.

A sequência padrão pode ser informalmente descrita como uma "travessia em profundidade que manipula nós quando eles são primeiro encontrados, em vez de fazê-lo durante o retrocesso."

Eu tenho uma necessidade real de pesquisa em largura. Como posso fazer com que find se comporte dessa maneira?

Para ilustração, com a seguinte configuração:

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

find tem o seguinte comportamento padrão:

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

e com -depth , ele executa da seguinte forma:

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

No entanto, o que eu quero é a seguinte opção (fictícia):

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

Em outras palavras, eu preciso de find para processar / relatar todos arquivos / dirs a uma determinada profundidade antes de prosseguir.

Como posso fazer isso?

    
por Wildcard 29.04.2016 / 02:28

4 respostas

5

Você pode fazer isso apenas com curingas de shell. Construa um padrão com progressivamente mais níveis de diretório.

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

Isso perde os arquivos de pontos. Use FIGNORE='.?(.)' no ksh, shopt -s dotglob no bash ou setopt glob_dots no zsh para incluí-los.

Advertências:

  • Isso explodirá a memória se houver muitos arquivos.
  • Isso atravessa links simbólicos para diretórios de forma recursiva.

Se você quiser escolher a ordem ou diretórios e não diretórios, e o desempenho não é crítico, você pode fazer duas passagens e testar [ -d "$file" ] em cada passagem.

    
por 29.04.2016 / 02:59
2

Você pode canalizar seu find para uma classificação ordenada principalmente pelo número de / caracteres no nome do caminho. Por exemplo,

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

Isso usa awk para prefixar o nome do caminho com o número de barras e sed para remover esse prefixo no final.

Na verdade, como você provavelmente quer que o conteúdo do diretório alpha/charlie+ seja listado após alpha/charlie , você precisa dizer sort -t/ -k1,1 -k2,2 -k3,3 -k4,4 até a profundidade desejada.

    
por 29.04.2016 / 19:50
0

# cat ./bfind

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

Isso funciona aumentando a profundidade de find e repetindo, acho que pode repetir resultados, mas pode ser facilmente filtrado

    
por 05.07.2017 / 07:17
0

Outra resposta não baseada em 'find' mas no bash - use o "comprimento do diretório pai" primeiro, depois classifique por alfa.

A resposta não coincide, já que seus resultados têm "charlie, bravo, delta", mas eu me perguntei se deveria ser "bravo, charlie, delta" em ordem alfabética.

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

Isso produz

  $ 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
    
por 09.04.2018 / 22:05

Tags