Como excluir um diretório na localização. comando

1380

Estou tentando executar um findcomando para todos os arquivos JavaScript, mas como excluo um diretório específico?

Aqui está o findcódigo que estamos usando.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
helion3
fonte
10
Qual é o diretório que você precisa excluir?
The Archetypal Paul
11
É melhor usar find ... | while read -r file .... Além disso, é melhor aceitar e aprovar respostas.
Pausado até novo aviso.
enquanto leitura é lenta, pois é mais rápido
mpapis
18
O @mpapis durante a leitura lida corretamente com linhas completas com espaço em branco.
Jean-Philippe Pellet
1
Basta executar isso em uma pasta com arquivos com espaços em seus nomes: for file in $(find .); do echo "$file"; done. Nomes com espaços são divididos, o que não queremos.
Jean-Philippe Pellet

Respostas:

1140

Use o -pruneinterruptor. Por exemplo, se você deseja excluir o miscdiretório, adicione a -path ./misc -prune -oao seu comando find:

find . -path ./misc -prune -o -name '*.txt' -print

Aqui está um exemplo com vários diretórios:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Aqui nós excluímos dir1 , dir2 e dir3 , pois nas findexpressões é uma ação que age com base nos critérios -path dir1 -o -path dir2 -o -path dir3(se dir1 ou dir2 ou dir3 ), ANDed with type -d.

Outra ação é -o printapenas imprimir.

f10bit
fonte
89
Hmm. Isso também não funciona para mim, pois incluirá o diretório ignorado "./misc" na saída.
Theuni 12/12/12
84
@ Theuni Provavelmente não funcionou para você porque você não adicionou uma -print(ou qualquer outra ação) explicitamente depois -name. Nesse caso, os dois "lados" da -oimpressão acabam, enquanto que, se você usar -print, apenas esse lado é impresso.
Daniel C. Sobral
4
Da página de manual: Because -delete implies -depth, you cannot usefully use -prune and -delete together.Então, como faço para excluir com o find se quero excluir diretórios específicos da exclusão?
Jānis Elmeris
15
Para remover todo o próprio diretório do uso resultados: find . -not -path "./.git*". Usar em ./dir*vez de ./dir/*remove o diretório e o conteúdo da saída.
Micahblu
64
Esta pergunta e a confusão nas respostas são um manifesto sobre o quanto a interface do usuário find corresponde ao que as pessoas precisam.
Johannes Overmann
1932

Se -prunenão funcionar para você, isso irá:

find -name "*.js" -not -path "./directory/*"

Advertência: requer percorrer todos os diretórios indesejados.

Liberta-te
fonte
86
Um dos comentários na resposta aceita aponta o problema. -prunenão exclui o diretório em si, exclui seu conteúdo, o que significa que você obterá uma linha indesejada na saída com o diretório excluído.
GetFree
96
Ótima resposta. Eu acrescentaria que você pode excluir um diretório em QUALQUER nível, alterando o primeiro .para *. portanto find -name "*.js" -not -path "*/omitme/*", omitiria arquivos de um diretório chamado "omitme" em qualquer nível de profundidade.
DeeDee
83
No entanto, ele ainda percorre todo o diretório indesejado. Estou adicionando minha própria resposta. :-)
Daniel C. Sobral
18
Observe, no entanto, que a opção de remoção apenas não funcionará se você não usar -printexplicitamente.
Daniel C. Sobral
39
Seria melhor dizer "Esta é uma alternativa ao uso de -prune". As respostas sugerindo -une não estão claramente erradas, elas simplesmente não são do jeito que você faria.
Jimbo
458

Acho que é mais fácil raciocinar a seguir do que outras soluções propostas:

find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

Nota importante: os caminhos digitados depois -pathdevem corresponder exatamente ao que findseria impresso sem a exclusão. Se esta frase confunde apenas certifique-se de usar caminhos completos através do todo comando como este: . Veja a nota [1] se você quiser entender melhor.find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...

Por dentro \(e \)é uma expressão que corresponderá exatamente build/external (veja a nota importante acima) e, com sucesso, evitará atravessar qualquer coisa abaixo . Isso é então agrupado como uma única expressão com parênteses escapados e prefixado com o -notqual fará com que findpule qualquer coisa que corresponda a essa expressão.

Pode-se perguntar se a adição -notnão fará com que todos os outros arquivos ocultos -prunereapareçam, e a resposta é não. A maneira como -prunefunciona é que tudo o que, uma vez alcançado, os arquivos abaixo desse diretório são permanentemente ignorados.

Isso vem de um caso de uso real, no qual eu precisava chamar o yui-compressor em alguns arquivos gerados pelo wintersmith, mas deixar de fora outros arquivos que precisam ser enviados como estão.


Nota [1] : Se você deseja excluir /tmp/foo/bare executar o find como este " find /tmp \(...", deverá especificar -path /tmp/foo/bar. Se, por outro lado, você executar encontrar assim cd /tmp; find . \(..., deverá especificar -path ./foo/bar.

Daniel C. Sobral
fonte
37
Excelente resposta, obrigado. Isso funciona e é escalável (legível) para várias exclusões. Vocês são senhores e estudiosos, senhor. Obrigado pelo exemplo para várias exclusões
Freedom_Ben
7
Isso não funciona se eu quiser usar a opção -delete:find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
Jānis Elmeris
17
@ Janis Você pode usar em -exec rm -rf {} \;vez de -delete.
Daniel C. Sobral
11
Examinando a saída de find, isso é óbvio, na verdade, mas me deixou de fora. Se você está procurando no diretório atual (especificando .como o caminho de pesquisa, ou não especificar um em tudo), você provavelmente vai querer o seu padrão depois -pathde começar com ./, por exemplo: find -not \( -path ./.git -prune \) -type f.
Zantier 9/10
7
Uma variação mais precisa (e compatível com POSIX) deste método: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)seguida de quaisquer condições que devem corresponder ao que você está procurando.
Walf
218

Há claramente alguma confusão aqui sobre qual deveria ser a sintaxe preferida para ignorar um diretório.

Opinião GNU

To ignore a directory and the files under it, use -prune

Na página de manual do GNU find

Raciocínio

-prunepára findde descer para um diretório. Apenas especificar -not -pathcontinuará no diretório ignorado , mas -not -pathserá falso sempre que findtestar cada arquivo.

Problemas com -prune

-prune faz o que se destina, mas ainda há algumas coisas que você precisa cuidar ao usá-lo.

  1. find imprime o diretório removido.

    • VERDADEIRO Esse é o comportamento pretendido, apenas não desce a ele. Para evitar a impressão completa do diretório, use uma sintaxe que o omita logicamente.
  2. -prunesó funciona com -printe sem outras ações.

    • NÃO É VERDADEIRO . -prunefunciona com qualquer ação, exceto -delete. Por que não funciona com exclusão? Para -deletefuncionar, encontre as necessidades de percorrer o diretório na ordem DFS, já -deleteque primeiro excluirá as folhas, depois os pais das folhas, etc ... Mas, para especificar -pruneque faz sentido, é findnecessário acessar um diretório e parar de descer, claramente não faz sentido com -depthou -deleteligado.

atuação

Configurei um teste simples das três principais respostas votadas para essa pergunta (substituídas -printpor -exec bash -c 'echo $0' {} \;para mostrar outro exemplo de ação). Os resultados estão abaixo

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Conclusão

Ambos sintaxe do f10bit e sintaxe de Daniel C. Sobral tomou 10-25ms para executar em média. A sintaxe do GetFree , que não usa -prune, levou 865ms. Portanto, sim, este é um exemplo bastante extremo, mas se você se importa com o tempo de execução e está fazendo algo intensamente remotamente, deve usá-lo -prune.

Observe que a sintaxe de Daniel C. Sobral apresentou o melhor das duas -prunesintaxes; mas suspeito fortemente que esse seja o resultado de algum cache, pois a troca da ordem em que os dois foram executados resultou no resultado oposto, enquanto a versão sem remoção foi sempre mais lenta.

Script de teste

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup
Restabelecer Monica Please
fonte
18
Obrigado por uma análise muito boa. Em relação a "Eu suspeito fortemente que isso seja resultado de algum cache", você pode executar este comando: sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && free" para limpar o cache (consulte unix. stackexchange.com/questions/87908/… ).
Ndemou
Depois de alguns testes nesses dois com -prune, posso dizer que raramente há diferença. Tenha em mente que o comando começar a primeira irá beneficiar o desempenho da CPU, o mais tarde cpu aquecer> queda de desempenho causa menor devagar (eu fiz cache de purga antes de cada comando como sugestão @ndemou)
Huy.PhamNhu
Tente alternar o número name1() name2() name3()no script de teste do @BroSlow acima para alterar a ordem de execução e obter um visual do que eu disse. Na vida real, é imperceptível entre os dois.
Huy.PhamNhu
Aplausos. Obrigado por esta resposta de qualidade.
Stphane
Você não deve ser -o, o que significa ou. então você está podando na primeira etapa e depois esquecendo tudo sobre ela na próxima.
mmm
97

Este é o único que funcionou para mim.

find / -name MyFile ! -path '*/Directory/*'

Procurando por "MyFile" excluindo "Diretório". Dê ênfase às estrelas *.

DimiDak
fonte
13
Este método funciona no macOS, enquanto a resposta aceita não. Eu sei que a pergunta original é para Linux.
Xavier Rubio Jansana
5
Note que você pode adicionar múltiplos ! -path '*/Directory/*'ao seu comando em sucessão a ignorar vários diretórios
Aclwitt
Funciona no MacOS, mas não no linux ... confirmado
Marcello de Sales
Em uma docker containersó funciona comsh -c "find..."
Marcello de Sales
@ Marcello de Sales Claro que funciona no Linux.
DimiDak 16/01
59

Uma opção seria excluir todos os resultados que contêm o nome do diretório com grep. Por exemplo:

find . -name '*.js' | grep -v excludeddir
Joshua
fonte
44
Isso tornará a sua pesquisa muito lenta
Dorian
6
Este funcionou para mim, outros (que usam -prune) - não.
Andron 28/03
7
Lento em grandes resultados, mas útil em conjuntos menores. Mas como excluir vários diretórios usando grep? Claro que assim: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3mas pode haver uma maneira grep.
Timo Kähkönen
6
Se você quiser executar várias greps então você seria melhor escrevê-lo como expressões regulares: egrep -v '(dir1|dir2|dir3)'. No entanto, neste estudo de caso específico, seria melhor excluir diretórios dentro de findsi.
Laurence
1
sim, e você não precisa de parênteses e seria melhor usar ^ para garantir que ele corresponda ao nome do diretor no início da string, por exemplo: find. -name '* .js' | egrep -v "^ \ ./ excluido1 | ^ \ ./ excluido2"
Sofija
41

Eu prefiro a -notnotação ... é mais legível:

find . -name '*.js' -and -not -path directory
mpapis
fonte
5
Desculpe, não funciona. A página do manual finddiz: "Para ignorar um diretório e os arquivos nele, use -prune".
Christian Davén
8
Isto está errado. Isso não impede que a localização entre no diretório e atravesse todos os arquivos.
GetFree
find . -iname '*' -and -not -path './somePath'não impede que ele entre no referido diretório.
Lemmings19
Isso me ajudou com o caminho .git find . -iname '*' -not -path './.git/*'
Mark Shust em M.academy
7
@rane: Mais especificamente, find . -not -path "*/.git*"seria o que você deseja.
Ben
20

Use a opção -prune. Então, algo como:

find . -type d -name proc -prune -o -name '*.js'

O '-type d -name proc -prune' procura apenas os diretórios chamados proc para excluir.
O '-o' é um operador 'OR'.

Drew Frezell
fonte
1
Esta é a única solução pura de "encontrar" que funcionou para mim. Os diretórios que eu desejava excluir NÃO estão imediatamente abaixo do diretório de trabalho atual.
22613
5
No entanto, adicionar -printao final pode melhorar os resultados. find . -type d -name .hg -prune -o -name dataignorou o conteúdo dos .hgdiretórios (múltiplos) , mas listou os .hgpróprios diretórios. Com -print, ele listou apenas os diretórios "dados" que eu estava procurando.
precisa
19

-prunedefinitivamente funciona e é a melhor resposta, pois impede a descida no diretório que você deseja excluir. -not -pathque ainda pesquisa o diretório excluído, simplesmente não imprime o resultado, o que pode ser um problema se o diretório excluído estiver montado no volume da rede ou se você não tiver permissões.

A parte complicada é que findé muito particular a ordem dos argumentos; portanto, se você não os acertar, seu comando pode não funcionar. A ordem dos argumentos é geralmente a seguinte:

find {path} {options} {action}

{path}: Coloque todos os argumentos relacionados ao caminho primeiro, como . -path './dir1' -prune -o

{options}: Eu tenho mais sucesso ao colocar -name, -iname, etccomo a última opção neste grupo. Por exemplo-type f -iname '*.js'

{action}: Você deseja adicionar -printao usar-prune

Aqui está um exemplo de trabalho:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print
wisbucky
fonte
16

Este é o formato que eu usei para excluir alguns caminhos:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

Eu usei isso para encontrar todos os arquivos que não estão nos caminhos ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
user1882879
fonte
Eu tentei isso e ele ainda desce nos diretórios, então a velocidade definitivamente não é melhorada.
Br.Bill 29/08/19
10

A abordagem -path -prune também funciona com curingas no caminho. Aqui está uma instrução find que encontrará os diretórios de um servidor git que atende a vários repositórios git, deixando de fora os diretórios internos do git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  
Wolfgang Fahl
fonte
9

Para excluir vários diretórios:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

Para adicionar diretórios, adicione -o -path "./dirname/*":

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

Mas talvez você deva usar uma expressão regular , se houver muitos diretórios a serem excluídos.

JBENOIT
fonte
9

Há muitas respostas boas, levei algum tempo para entender para que serviam cada elemento do comando e a lógica por trás dele.

find . -path ./misc -prune -o -name '*.txt' -print

find começará a encontrar arquivos e diretórios no diretório atual, daí o find ..

A -oopção representa um OR lógico e separa as duas partes do comando:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

Qualquer diretório ou arquivo que não seja o diretório ./misc não passará no primeiro teste -path ./misc. Mas eles serão testados contra a segunda expressão. Se o nome deles corresponder ao padrão, *.txteles serão impressos, devido ao-print opção.

Quando a localização atinge o diretório ./misc, esse diretório satisfaz apenas a primeira expressão. Portanto, a -pruneopção será aplicada a ele. Diz ao comando find para não explorar esse diretório. Portanto, qualquer arquivo ou diretório em ./misc nem será explorado pelo find, não será testado na segunda parte da expressão e não será impresso.

Istopopoki
fonte
Todo mundo tem uma solução, mas a sua explicou o melhor. Eu estava convencido de que -name fosse usado primeiro em vez de -path. Sua explicação foi adequada para chegar ao que eu queria. encontrar . -name "* .txt" -print -o -path ./misc -prune
Vendetta V
7

Para uma solução funcional (testada no Ubuntu 12.04 (Precise Pangolin)) ...

find ! -path "dir1" -iname "*.mp3"

procurará por arquivos MP3 na pasta e nas subpastas atuais, exceto na subpasta dir1.

Usar:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... para excluir dir1 AND dir2

James Dupin
fonte
Não funciona para mim. Nem nenhuma das respostas acima. Chapéu vermelho.
Tharpa 14/01
6

um bom truque para evitar a impressão dos diretórios removidos é usar -print(também funciona -exec) depois do lado direito do -ordepois -prune. Por exemplo, ...

find . -path "*/.*" -prune -or -iname "*.j2"

imprimirá o caminho de todos os arquivos abaixo do diretório atual com a extensão `.j2", ignorando todos os diretórios ocultos. Limpo. Mas também imprimirá o caminho completo de cada diretório que estiver sendo ignorado, conforme observado acima. a seguir não, ...

find . -path "*/.*" -prune -or -iname "*.j2" -print

porque logicamente há um oculto -andapós o -inameoperador e antes da impressão. Isso o vincula à parte correta da -orcláusula devido à ordem booleana de operações e associatividade. Mas os documentos dizem que há um oculto -printse ele (ou qualquer um de seus primos ... -print0, etc) não for especificado. Então, por que a parte esquerda da -orimpressão não está? Aparentemente (e eu não entendi isso desde a primeira leitura da página de manual), isso é verdade se não houver apenas operadores descritivos aparentemente não faria nada, então acho que faz sentido. Como mencionado acima, tudo isso também funciona ; portanto, a seguir, é exibida uma lista completa de cada arquivo com a extensão desejada, mas não listando o primeiro nível de cada diretório oculto, ...-print - ou -execEM QUALQUER LUGAR, nesse caso, - a impressão é logicamente espalhada em torno de tal forma que tudo seja impresso. Se mesmo UMprint operação no estilo - é expressa em qualquer cláusula, todas essas lógicas ocultas desaparecem e você obtém apenas o que deseja. especificamos. Agora, francamente, eu poderia ter preferido o contrário, mas então umfind-execls -la

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

Para mim (e outras pessoas neste segmento), a findsintaxe fica bem barroca muito rapidamente, então eu sempre uso parênteses para ter certeza de que sei o que se liga ao que, então eu geralmente crio uma macro para capacidade de digitação e forma todas as declarações como. ..

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

É difícil dar errado, configurando o mundo em duas partes dessa maneira. Espero que isso ajude, embora pareça improvável que alguém leia até a 30ª resposta e vote, mas pode-se esperar. :-)

cycollins
fonte
5

Você pode usar a opção de remoção para conseguir isso. Como por exemplo:

find ./ -path ./beta/* -prune -o -iname example.com -print

Ou a opção inversa grep "grep -v":

find -iname example.com | grep -v beta

Você pode encontrar instruções e exemplos detalhados no comando Linux find, excluindo diretórios da pesquisa .

Siju V
fonte
A solução grep é a única que exclui todos os diretórios com o mesmo nome. Ao tentar excluir "node_modules", isso é bastante útil.
precisa saber é o seguinte
3
@bmacnaughton - não é verdade! Eu vim aqui especificamente procurando excluir "node_modules" e depois de ler muitas respostas ótimas, decidi find . -type f -print -o -path "*/node_modules" -pruneusar ... o caractere curinga que ignora "node_modules" em qualquer nível; o uso -printna primeira alternativa -type f -printfaz com que apenas essa parte seja impressa, portanto os diretórios "node_modules" não são listados. (que pode também ser invertida: find . -path "*/node_modules" -prune -o -type f -print)
Stephen P
o que está fazendo lá? Qual é o arquivo exato que você deseja excluir? Você está usando-o como curinga?
Siju V 23/02/19
1
@ StephenP, obrigado por apontar isso; Aprendi a diferença entre usar ./node_modulese usar */node_modules. No meu caso, onde node_modulesexiste apenas no diretório em que inicio a pesquisa (e nesse node_modulesdiretório), posso usá-lo find . -type f -print -o -path "./node_modules" -prune porque não haverá um node_modulesdiretório em nenhum outro diretório.
bmacnaughton
1
@SijuV - no diretório em que eu estava pesquisando havia um node_modulessubdiretório, mas também havia subdiretórios que tinham seus próprios node_modules ... usando ./node_modulescorrespondências apenas ao subdiretório node_modulesno diretório atual .e removendo-o; usar */node_modulescorresponde e remove o diretório a qualquer profundidade, porque o *as glob corresponde a qualquer prefixo do caminho inicial, como ./test5/main/node_modules, não apenas o ./prefixo. O *é um curinga, mas como um glob não como um regex.
Stephen P
5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
O Arquetípico Paulo
fonte
Não é possível fazer com que este funcione. find ~/Projects -name '*.js' -\! -name 'node_modules' -pruneainda está transformando-se arquivos com node_modulesem seu caminho
MPEN
1
@pen, Em stackoverflow.com/questions/4210042/… , aprendi que a sintaxe que você deseja é find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print. O nome desse caminho deve corresponder exatamente ao que a impressão seria impressa para imprimir o diretório.
PatS
4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

parece funcionar da mesma forma que

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

e é mais fácil lembrar da IMO.

Funkodebat
fonte
4

TLDR: entenda seus diretórios raiz e adapte sua pesquisa a partir daí, usando a -path <excluded_path> -prune -oopção Não inclua um final /no final do caminho excluído.

Exemplo:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


Para usar efetivamente o find, acredito que é imperativo ter um bom entendimento da estrutura de diretórios do sistema de arquivos. No meu computador doméstico, eu tenho discos rígidos com vários TB, com cerca de metade desse conteúdo sendo copiada usando rsnapshot(ou seja, rsync). Embora faça backup em uma unidade fisicamente independente (duplicada), ela é montada no /diretório raiz ( ) do meu sistema /mnt/Backups/rsnapshot_backups/::

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

O /mnt/Backups/rsnapshot_backups/diretório atualmente ocupa ~ 2,9 TB, com ~ 60M de arquivos e pastas; simplesmente atravessar esses conteúdos leva tempo:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

Assim, sempre que eu precisar procurar um arquivo na minha /partição (raiz), preciso lidar com (evitar se possível) atravessar minha partição de backups.


EXEMPLOS

Entre as abordagens sugeridas de várias maneiras neste tópico ( Como excluir um diretório no comando find. ), Acho que as pesquisas usando a resposta aceita são muito mais rápidas - com ressalvas.

Solução 1

Digamos que desejo encontrar o arquivo do sistema libname-server-2.a, mas não desejo pesquisar nos meus rsnapshotbackups. Para localizar rapidamente um arquivo do sistema, use o caminho de exclusão /mnt(por exemplo, use /mnt, not /mnt/, ou /mnt/Backups, ou ...):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

... encontra esse arquivo em apenas alguns segundos, enquanto isso leva muito mais tempo (parecendo ser repetido em todos os diretórios "excluídos"):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

Solução 2

A outra solução oferecida neste segmento ( SO # 4210042 ) também apresenta desempenho ruim:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

RESUMO CONCLUSÕES

Use a abordagem ilustrada em " Solução 1 "

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

ie

... -path <excluded_path> -prune -o ...

observando que sempre que você adiciona a /trilha ao caminho excluído, o findcomando entra recursivamente nos /mnt/*diretórios (todos esses) - que, no meu caso, por causa dos /mnt/Backups/rsnapshot_backups/*subdiretórios, inclui adicionalmente ~ 2,9 TB de arquivos a serem pesquisados! Ao não anexar uma trilha, /a pesquisa deve ser concluída quase imediatamente (em segundos).

A "Solução 2" ( ... -not -path <exclude path> ...) também parece procurar recursivamente os diretórios excluídos - não retornando correspondências excluídas, mas consumindo desnecessariamente esse tempo de pesquisa.


Pesquisando nesses rsnapshotbackups:

Para localizar um arquivo em um dos meus rsnapshotbackups horários / diários / semanais / mensais ):

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

Excluindo um diretório aninhado:

Aqui, quero excluir um diretório aninhado, por exemplo, /mnt/Vancouver/projects/ie/claws/data/*ao pesquisar em /mnt/Vancouver/projects/:

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

Além: A adição -printno final do comando suprime a impressão do diretório excluído:

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
Victoria Stuart
fonte
Não é o tamanho dos arquivos que fica lento find, é o número de entradas de diretório que ele deve examinar. Portanto, é muito pior se você tiver muitos, muitos arquivos pequenos (especialmente se todos estiverem multiplamente vinculados!) Do que se você tiver apenas um punhado de arquivos com vários gigabytes.
quer
@ TobySpeight: bom ponto. Mencionei o tamanho do espaço de pesquisa para indicar a escala, que também contém muitos arquivos. Uma pesquisa rápida de raiz (/) com sudo ls -R / | wc -lindica ~ 76,5 milhões de arquivos (a maioria dos quais é copiada, exceto arquivos de sistema "não configurados"); /mnt/Vancouver/com ls -R | wc -lindica ~ 2.35M arquivos; /home/victoria/contém 0,668 milhões de arquivos.
Victoria Stuart
4

Você também pode usar expressões regulares para incluir / excluir alguns arquivos / direcionar sua pesquisa usando algo como isto:

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

Isso fornecerá apenas todos os arquivos js, vue, css, etc, mas excluindo todos os arquivos nas pastas node_modulese vendor.

supersan
fonte
3

Eu estava usando findpara fornecer uma lista de arquivos xgettexte queria omitir um diretório específico e seu conteúdo. Eu tentei muitas permutações de -pathcombinado com, -prunemas foi incapaz de excluir completamente o diretório que eu queria ir.

Embora eu tenha conseguido ignorar o conteúdo do diretório que eu queria ignorar, findretornei o próprio diretório como um dos resultados, o que causou xgettextuma falha como resultado (não aceita diretórios; apenas arquivos).

Minha solução foi simplesmente usar grep -vpara pular o diretório que eu não queria nos resultados:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

Se existe ou não um argumento para findisso funcionará 100%, não posso dizer com certeza. O uso grepfoi uma solução rápida e fácil após algumas dores de cabeça.

Lemmings19
fonte
3

Nenhuma das respostas anteriores é boa no Ubuntu. Tente o seguinte:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

Eu encontrei isso aqui

sixro
fonte
Não vejo nenhuma razão para que nenhuma das respostas com mais de 100 pontos não funcione no Ubuntu.
Axel Beckert 02/09
mmm vamos ver? talvez porque eu tentei todos eles?
sixro 01/04
O find encontra em toda parte a mesma implementação em todas as distribuições Linux - a do projeto GNU. A única diferença pode ser as versões. Mas as mudanças na década passada não foram tão invasivas, exceto talvez pela correspondência de permissão.
Axel Beckert
3

Isso é adequado para mim em um Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

Ele excluirá vendore dirá o app/cachenome da pesquisa com o sufixo php.

jiahut
fonte
É melhor colocar aspas simples em torno de '* .php' ou você não encontrará o que está procurando.
Br.Bill 29/08/19
3

Para aqueles em versões mais antigas do UNIX que não podem usar -path ou -not

Testado no SunOS 5.10 bash 3.2 e no SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f
JaredTS486
fonte
Pode passar mais do que o diretório especificado.
MUY Bélgica
2

Como usar a opção de podar-de-encontrar-em-sh é uma excelente resposta de Laurence Gonsalves sobre como -prunefunciona.

E aqui está a solução genérica:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

Para evitar digitar /path/to/seach/várias vezes, envolva o findem um pushd .. popdpar.

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd
go2null
fonte
1
Em stackoverflow.com/questions/4210042/… , aprendi que a sintaxe usada para -pathdeve corresponder ao nome que a impressão seria impressa se fosse para imprimir o diretório, por exemplo, por exemplo find . -path ./.git -prune -o -print, ou find $HOME/foo -path $HOME/foo/.git -prune -o -print Algumas das respostas dizem apenas -path somedirque infelizmente é não é exato o suficiente para ser útil.
PatS 5/08/19
2

Para o que eu precisava, funcionou assim, encontrando landscape.jpgem todos os servidores a partir do root e excluindo a pesquisa no /vardiretório:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type dlista todos os d diretórios em/

grep -v /var exclui `/ var 'da lista

xargs -I '{}' find '{}' -name landscape.jpgexecute qualquer comando, como findem cada diretório / resultado da lista

adrianTNT
fonte
Espere um segundo, /ainda não está excluído. Você pode precisar sed 1d.
Simba
2

Os seguintes comandos funcionam:

find . -path ./.git -prune -o -print

Se você tiver um problema com a localização, use a -D treeopção para visualizar as informações da análise de expressão.

find -D tree . -path ./.git -prune -o -print

Ou o -D all, para ver todas as informações de execução.

find -D all . -path ./.git -prune -o -print
EIIPII
fonte
1

Encontrei o nome das funções nos arquivos de origem C excluindo * .o e exclua * .swp e exclude (arquivo não regular) e exclua a saída dir com este comando:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach
Ivan Ivanovich
fonte
1

Melhor usar a execação que o forloop:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

O exec ... '{}' ... '{}' \;será executado uma vez para cada arquivo correspondente, substituindo os chavetas '{}'pelo nome do arquivo atual.

Observe que os colchetes estão entre aspas simples para protegê-los da interpretação como pontuação do script do shell * .


Notas

* Na seção EXEMPLOS da find (GNU findutils) 4.4.2página de manual

Alberto
fonte
1
Pergunta muito antiga, mas ainda com espaço para melhorias. Achei por acaso tentar resolver um problema semelhante, e nenhuma das respostas foi satisfatória.
Alberto
Uso a execação com frequência e acho muito útil. Eu normalmente adiciono aspas entre o {}caso de haver espaços nos caminhos do arquivo que são fornecidos "{}".
Ludovic Kuty
@lkuty Eu estava prestes a editar minha postagem para refletir seu comentário, mas após um teste rápido (sem citação, {}funciona para arquivos com espaços em branco em seus nomes) e uma olhada nas páginas do manual, parece que a citação é necessária apenas para evitar que eles sejam mal interpretados como pontuação do script de shell. Nesse caso, você usaria aspas simples:'{}'
Alberto
Eu acho que tive que usá-lo para fazer cpou mvou rm. Eu vou dar uma olhada
Ludovic Kuty
1

Eu tentei o comando acima, mas nenhum dos que usam "-prune" funciona para mim. Eventualmente, eu tentei isso com o comando abaixo:

find . \( -name "*" \) -prune -a ! -name "directory"
Jolly Liu
fonte