Bulma dizini nasıl hariç tutulur. komuta


1380

findTüm JavaScript dosyaları için bir komut çalıştırmaya çalışıyorum , ancak belirli bir dizini nasıl hariç tutabilirim?

İşte kullandığımız findkod.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

10
Hariç tutmanız gereken dizin nedir?
Arketipik Paul

11
Kullanmak daha iyi find ... | while read -r file .... Ayrıca, cevapları kabul etmek ve onaylamak daha iyidir.
sonraki duyuruya kadar duraklatıldı.

okurken yavaş, çünkü daha hızlı
mpapis

18
@mpapis okurken tam satırları boşlukla doğru şekilde işler.
Jean-Philippe Pellet

1
Sadece adlarında boşluk içeren dosyaları ile bir klasörde bu çalıştırın: for file in $(find .); do echo "$file"; done. Boşluklu isimler bölünmez, istemiyoruz.
Jean-Philippe Pellet

Yanıtlar:


1140

-pruneAnahtarı kullanın . Örneğin, miscdizini hariç tutmak istiyorsanız -path ./misc -prune -ofind komutunuza a ekleyin :

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

Birden çok dizin içeren bir örnek:

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

Burada dir1 , dir2 ve dir3'ü hariç tutuyoruz , çünkü findifadelerde bu kriterler -path dir1 -o -path dir2 -o -path dir3( dir1 veya dir2 veya dir3 ise ) ve ( ve) ile hareket eden bir eylemdir type -d.

Diğer eylem -o print, sadece yazdırmak.


89
Hmm. Çıktıya yok sayılan "./misc" dizinini içereceği için bu da benim için çalışmaz.
Theuni

84
@Theuni Muhtemelen sizin için işe yaramadı çünkü -printaçık bir şekilde (veya başka bir eylem) eklemediniz -name. Bu durumda, her iki "tarafı" -oyazdırmayı sonlandırırken, kullanırsanız -printyalnızca bu tarafı yazdırır.
Daniel C.Sobral

4
Manpage'den: Because -delete implies -depth, you cannot usefully use -prune and -delete together.Peki, belirli dizinleri silme işleminden hariç tutmak istiyorsam find ile silmeye nasıl devam edebilirim?
Jānis Elmeris

15
Sonuçlar kullanımından dizinin tamamını kendisi kaldırmak için: find . -not -path "./.git*". ./dir*Bunun yerine kullanılması ./dir/*, dizinin yanı sıra içeriği de çıktıdan kaldırır.
micahblu

64
Bu soru ve cevaplardaki karışıklık, bulma kullanıcı arayüzünün insanların ihtiyaç duyduğu şeyle ne kadar kötü eşleştiğinin bir tezahürüdür.
Johannes Overmann

1931

Eğer -prunesizin için çalışmaz, bu yapacaktır:

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

Uyarı: istenmeyen tüm dizinlerin geçişini gerektirir.


86
Kabul edilen cevaptaki yorumlardan biri sorunu işaret ediyor. -prunedizinin kendisini hariç tutmaz, içeriğini hariç tutar; bu, hariç tutulan dizine sahip çıktıda istenmeyen bir satır elde edeceğiniz anlamına gelir.
GetFree

95
Mükemmel cevap. Seni ilk değiştirerek HERHANGİ düzeyde bir dizin hariç tutabilmek Bu eklemek istiyorum .To *. bu yüzden find -name "*.js" -not -path "*/omitme/*"herhangi bir derinlikte "omitme" adlı bir dizinden dosyaları atlar.
DeeDee

83
Hala geçtiği olsa istenmeyen dizinin tüm. Kendi cevabımı ekliyorum. :-)
Daniel C. Sobral

18
Ancak, budama seçeneğinin yalnızca -printaçıkça kullanmıyorsanız işe yaramadığını unutmayın .
Daniel C.Sobral

39
"Bu, -prune kullanmaya bir alternatiftir" demek daha iyi olur. -Purun öneren cevaplar açıkça yanlış değildir, sadece sizin yaptığınız gibi değildir.
Jimbo

458

Aşağıdakilerin akıl yürütmesini diğer önerilen çözümlerden daha kolay buluyorum:

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

Önemli Not: Sonrasında yazdığınız yollar , hariç tutulmadan yazdırılacak yollarla -pathtam olarak eşleşmelidir find. Bu cümle sadece yapmak karıştırır Eğer emin dışarı aracılığıyla tam yollarını kullanmaya bütün böyle komuta: . Daha iyi bir anlayış istiyorsanız not [1] 'e bakınız.find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...

İçeride \(ve tam olarak\) eşleşecek bir ifadedir (yukarıdaki önemli nota bakın) ve başarı üzerine aşağıdaki herhangi bir şeyden kaçınmaktan kaçınacaktır . Bu daha sonra kaçan parantez tek bir ifade olarak gruplandırılmış ve öneki hangi yapacak o ifadesinin eşleştiği edildi atlama şey. build/external-notfind

Ekleme, -nottüm diğer dosyaların -pruneyeniden görünerek gizlenip gizlenmeyeceğini sorabilir ve yanıt hayırdır. Çalışma şekli -prune, ulaşıldıktan sonra bu dizinin altındaki dosyaların kalıcı olarak yoksayıldığı her şeydir.

Bu, wintersmith tarafından oluşturulan bazı dosyalarda yui-kompresör çağırmak, ancak olduğu gibi gönderilmesi gereken diğer dosyaları dışarıda bırakmak için gereken gerçek bir kullanım durumundan geliyor.


Not [1] : Hariç tutmak istiyorsanız /tmp/foo/barve " find /tmp \(..." gibi bulmayı çalıştırıyorsanız , belirtmeniz gerekir -path /tmp/foo/bar. Öte yandan böyle bulursanız cd /tmp; find . \(...belirtmeniz gerekir -path ./foo/bar.


37
Mükemmel cevap, teşekkür ederim. Bu çalışır ve birden fazla hariç tutma için ölçeklenebilir (okunabilir). Siz bir bey ve bilginsiniz. Birden çok hariç tutma örneği için teşekkür ederiz
Freedom_Ben

7
-Delete anahtarını kullanmak istersem bu işe yaramaz: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 Bunun -exec rm -rf {} \;yerine kullanabilirsiniz -delete.
Daniel C. Sobral

11
Çıktılarını inceleyerek find, bu gerçekten açık, ama beni tetikledi. Eğer (belirterek geçerli dizinde arama yapıyorsanız .hiç birini belirterek arama yolu olarak, ya da değil), büyük olasılıkla sonra deseni istediğiniz -pathbaşlamak ./örn: find -not \( -path ./.git -prune \) -type f.
Zantier

7
Bu yöntemin daha hassas (ve POSIX uyumlu) bir varyasyonu: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)ardından aradığınızla eşleşmesi gereken koşullar.
Walf

217

Burada bir dizini atlamak için tercih edilen sözdiziminin ne olması gerektiği konusunda bazı karışıklıklar var.

GNU Görüşü

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

GNU bulma kılavuzu sayfasından

muhakeme

-prunefindbir dizine inmeyi durdurur . Sadece belirtmek -not -pathyine de atlanan dizine inecektir , ancak her dosyayı test -not -pathettiğinde yanlış olacaktır find.

İle ilgili sorunlar -prune

-prune istediği şeyi yapar, ancak yine de kullanırken dikkat etmeniz gereken bazı şeyler vardır.

  1. find budanmış dizini yazdırır.

    • DOĞRU Bu amaçlanan davranış, sadece onun içine inmiyor. Dizinin tamamen yazdırılmasını önlemek için dizini mantıksal olarak ihmal eden bir sözdizimi kullanın.
  2. -pruneyalnızca -printbaşka eylemlerle çalışır ve hiçbir işlem yapılmaz.

    • DOĞRU DEĞİL . -prunedışında herhangi bir eylemle çalışır -delete. Silme ile neden çalışmıyor? İçin -deleteişe, çünkü DFS sırayla dizin çapraz geçiş için ihtiyaçlarını bulmak -deleteilk ... Ama belirtmek için yaprak, yapraklar, vb sonra anne silecektir -prune, yapmak duygusuna findbunu inen bir dizin ve durak vurmak ihtiyaçları, hangi açık -depthya da -deleteaçık bir anlam ifade etmiyor .

Verim

Bu soruya en çok oylanan üç cevap için basit bir test oluşturdum ( başka bir eylem örneği göstermek için -printile değiştirildi -exec bash -c 'echo $0' {} \;). Sonuçlar aşağıda

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

Sonuç

Hem f10bit'in sözdizimi hem de Daniel C. Sobral'ın sözdizimi ortalama 10-25ms sürdü. GetFree'nin kullanmayan sözdizimi-prune 865 ms sürdü. Yani, evet, bu oldukça uç bir örnektir, ancak çalışma süresini önemsiyorsanız ve uzaktan yoğun bir şey yapıyorsanız kullanmalısınız -prune.

Not Daniel C. Sobral'ın sözdizimi iki -prunesözdiziminden daha iyi performans gösterdi ; ancak, bunun, budama olmayan sürüm her zaman en yavaş olduğu halde, ikisinin tersi sonuçla sonuçlandığı sırayı değiştirmek olarak bazı önbelleğe almanın bir sonucu olduğundan şüpheliyim.

Test Betiği

#!/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

18
Çok iyi bir analiz için teşekkürler. "Bunun bazı önbelleğe almanın bir sonucu olduğundan şüpheleniyorum" ile ilgili olarak şu komutu çalıştırabilirsiniz: sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && free" önbelleği temizlemek için (bkz. Unix. stackexchange.com/questions/87908/… ).
ndemou

-pruneBen bu iki üzerinde birkaç testten sonra nadiren herhangi bir fark olduğunu söyleyebiliriz. Hangi komut başlangıcının cpu performansından faydalanacağını unutmayın, daha sonra cpu ısınma> performans düşüşü küçük yavaşlamaya neden olur (her komuttan önce önbelleği @ndemou önerisi olarak temizledim)
Huy.PhamNhu

name1() name2() name3()Söylediklerim hakkında bir görsel almak için yürütme sırasını değiştirmek için yukarıdaki @BroSlow test komut dosyasında anahtar numarasını deneyin . Gerçek hayatta, bu ikisi arasında farkedilemez.
Huy.PhamNhu

Alkış. Bu kaliteli cevap için teşekkür ederim.
Stphane

-O anlamına gelmemeli veya. böylece ilk adımda budama yapıyorsunuz ve daha sonra bir sonraki adımda her şeyi unutuyorsunuz.
mmm

96

Benim için çalışan tek kişi bu.

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

"Dizin" hariç "Dosyam" aranıyor. Yıldızlara vurgu yapın *.


13
Bu yöntem, kabul edilen yanıt çalışmazken macOS üzerinde çalışır. Orijinal sorunun Linux için olduğunu biliyorum.
Xavier Rubio Jansana

5
Birden ! -path '*/Directory/*'fazla dizini yoksaymak için art arda komutunuza birden çok
öğe

MacOS üzerinde çalışıyor ancak linux üzerinde çalışmıyor ... onaylandı
Marcello de Sales

Sadece bir docker containerile çalışırsh -c "find..."
Marcello de Sales

@Marcello de Sales Tabii ki Linux üzerinde çalışıyor.
DimiDak

59

Seçeneklerden biri grep ile dizin adını içeren tüm sonuçları hariç tutmak olabilir. Örneğin:

find . -name '*.js' | grep -v excludeddir

44
Bu, aramanızı çok yavaşlatacaktır
Dorian

6
Bu benim için çalıştı, diğerleri (kullanan -prune) - değil.
Andron

7
Büyük sonuçlarda yavaş, ancak daha küçük setlerde faydalıdır. Ancak grep kullanarak birden çok dizini nasıl hariç tutabilirim? Tabii ki bu şekilde: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3ama bir grep yolu olabilir.
Timo Kähkönen

6
Birden greps gerçekleştirmek istiyorsanız o zaman normal ifadeler olarak yazmayı daha iyi olurdu: egrep -v '(dir1|dir2|dir3)'. Bununla birlikte, bu özel vaka çalışmasında, dizinleri findkendi içinde dışlamak daha iyi olacaktır .
Laurence

1
evet, parantezlere ihtiyacınız yoktur ve dizenin başındaki yönetmenadı ile eşleştiğinden emin olmak için ^ kullanmak daha iyi olur, örneğin: find. -adı '* .js' | egrep -v "^ \ ./ excludeddir1 | ^ \ ./ excludeddir2"
Sofija

41

-notGösterimi tercih ederim ... daha okunabilir:

find . -name '*.js' -and -not -path directory

5
Üzgünüm, çalışmıyor. For man sayfası find: "Bir dizini ve altındaki dosyaları yok saymak için -prune komutunu kullanın" der.
Christian Davén

8
Bu yanlış. Bulmanın dizine girmesini ve içindeki tüm dosyaların geçişini engellemez.
GetFree

find . -iname '*' -and -not -path './somePath'söz konusu dizine girmesini engellemez.
Lemmings19

Bu bana .git yolu ile yardımcı oldu find . -iname '*' -not -path './.git/*'
Mark Shust M.academy de

7
@rane: Daha spesifik find . -not -path "*/.git*"olarak istediğiniz şey olurdu.
Ben

20

-Prune seçeneğini kullanın. Yani, şöyle bir şey:

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

'-Type d -name proc -prune' yalnızca hariç tutulacak proc adlı dizinleri arar.
'-O' bir 'VEYA' operatörüdür.


1
Bu benim için işe yarayan tek saf "bul" çözümü. Dışlamak istediğim dizinler, geçerli çalışma dizininin hemen altında DEĞİLDİR.
Lambart

5
Ancak, -printsonuna eklemek sonuçları iyileştirebilir. find . -type d -name .hg -prune -o -name data(çoklu) .hgdizinlerin içeriğini görmezden geldi , ancak .hgdizinleri kendileri listeledi . İle -printsadece aradığım "veri" dizinleri listeledi.
Lambart

19

-pruneKesinlikle işe yarar ve en iyi cevaptır çünkü dışlamak istediğiniz direk içine inmeyi önler. -not -pathbu da hariç tutulan dizini ararsa, sonucu yazdırmaz; hariç tutulan dizin ağ birimine bağlıysa veya izinleriniz yoksa sorun olabilir.

Zor kısmı, findargümanların sırası hakkında çok özeldir, bu yüzden eğer onları doğru bulmazsanız, komutunuz çalışmayabilir. Argümanların sırası genellikle şöyledir:

find {path} {options} {action}

{path}: Yolla ilgili tüm argümanları önce koyun, örneğin . -path './dir1' -prune -o

{options}: -name, -iname, etcBu grupta son seçenek olarak en başarılı olanı seçtim . Örneğin-type f -iname '*.js'

{action}: -printKullanırken eklemek isteyeceksiniz-prune

İşte çalışan bir örnek:

# 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

16

Bu, bazı yolları hariç tutmak için kullandığım biçim:

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

Bunu ". *" Yollarında olmayan tüm dosyaları bulmak için kullandım:

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

Bunu denedim ve hala dizinlere iniyor, bu yüzden hız kesinlikle geliştirilmiyor.
Br. Fatura

10

-Path-prune yaklaşımı da yoldaki joker karakterlerle çalışır. Git dahili dizinlerini dışarıda bırakarak çoklu git depoları sunan bir git sunucusunun dizinlerini bulan bir find deyimi:

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 \)  

9

Birden çok dizini hariç tutmak için:

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

Dizin eklemek için şunu ekleyin -o -path "./dirname/*":

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

Ancak , hariç tutulacak çok dizin varsa, normal bir ifade kullanmalısınız .


9

Çok sayıda iyi cevap var, sadece komutun her bir unsurunun ne olduğunu ve arkasındaki mantığı anlamak biraz zaman aldı.

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

find, geçerli dizindeki dosyaları ve dizinleri bulmaya başlayacaktır. find . .

-oSeçenek mantıksal VEYA açılımı ve komuta iki bölümden ayırır:

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

./Misc dizini olmayan herhangi bir dizin veya dosya ilk sınamayı geçemez -path ./misc. Ancak ikinci ifadeye karşı test edilecektir. *.txtAdları, yazdırıldıkları desene karşılık geliyorsa ,-print seçenek .

Find ./misc dizinine ulaştığında, bu dizin yalnızca ilk ifadeyi karşılar. Böylece -pruneseçenek ona uygulanacaktır. Bu yapmak için bulma komutu söyler değil o dizini keşfetmek. Bu nedenle ./misc dosyasındaki herhangi bir dosya veya dizin find ile araştırılmayacak, ifadenin ikinci kısmına karşı test edilmeyecek ve yazdırılmayacaktır.


Herkesin bir çözümü var ama seninki bunu en iyi açıkladı. -Path yerine ilk olarak -name kullanılmasına kararlıydım. Açıklamanız istediğime ulaşmak için yeterliydi. bulmak. -name "* .txt" -print -o -yol ./misc -prune
Vendetta V

7

Çalışan bir çözüm için (Ubuntu 12.04 (Precise Pangolin) üzerinde test edilmiştir) ...

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

dir1 alt klasörü hariç, geçerli klasördeki ve alt klasörlerdeki MP3 dosyalarını arayacaktır.

kullanın:

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

... dir1 VE dir2'yi hariç tutmak için


Benim için çalışmıyor. Yukarıdaki yanıtların hiçbiri de böyle değildir. Kırmızı şapka.
Tharpa

6

budanmış dizinleri baskı kaçınmak için iyi bir hüner kullanımına olan -print(için çalışmalar -execsağ tarafında sonra sıra) -orsonrasÖ -prune. Örneğin, ...

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

geçerli dizinin altındaki tüm dosyaların yolunu, tüm gizli dizinleri atlayarak `.j2" uzantısıyla yazdıracaktır. takip etmez, ...

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

çünkü mantıksal olarak operatörden -andsonra -inameve -print'ten önce bir gizli var . Bu, -orboolean işlem sırası ve ilişkilendirilebilirlik nedeniyle maddeyi sağ tarafına bağlar . Ancak dokümanlar -print, (veya kuzenlerinden herhangi biri ... -print0vb.) Belirtilmezse gizli olduğunu söylüyor . Peki neden -orbaskının sol kısmı değil ? Görünüşe göre (ve bunu ilk adam sayfasını okuduğumdan anlamadım), eğer -print-veya herhangi bir -execyerde yoksa, bu durumda, -baskı mantıksal olarak her şeyin yazdırılacağı şekilde serpilirse doğrudur . Eğer BİR bileprint herhangi bir cümlede herhangi bir stil tarzı işlem , tüm bu gizli mantıksal olanlar gider ve sadece sizin belirttiğinizi alırsınız. Şimdi açıkçası, bunu başka bir şekilde tercih edebilirdim, ama sonra birfindsadece açıklayıcı operatörlerle görünüşte hiçbir şey yapmazdı, bu yüzden sanırım olduğu gibi mantıklı. Yukarıda belirtildiği gibi, bu -execda aynı şekilde çalışır, bu nedenle aşağıdakiler ls -la, istenen uzantıya sahip her dosya için tam bir liste verir , ancak her gizli dizinin ilk düzeyini listelemez, ...

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

Benim için (ve bu iş parçacığındaki diğerleri), findsözdizimi oldukça hızlı bir şekilde baroklaşıyor, bu yüzden her zaman neye bağlandığımdan emin olmak için parens atıyorum, bu yüzden genellikle tip yeteneği için bir makro oluşturuyorum ve tüm bu ifadeleri oluşturuyorum. ..

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

Dünyayı bu şekilde iki parçaya ayırarak yanlış gitmek zor. Umarım bu yardımcı olur, ancak herkesin 30 + th cevabını okuması ve oy vermesi olası görünmese de, umarım biri olabilir. :-)


5

Bunu elde etmek için budama seçeneğini kullanabilirsiniz. Örneğin olduğu gibi:

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

Veya ters grep “grep -v” seçeneği:

find -iname example.com | grep -v beta

Linux find komutunda ayrıntılı talimatlar ve örnekler bulabilirsiniz .


Grep çözümü, tüm dizinleri aynı adla hariç tutan tek çözümdür. "Düğüm_modülleri" ni hariç tutmaya çalışırken oldukça faydalıdır.
bmacnaughton

3
@bmacnaughton - doğru değil! Buraya özellikle "node_modules" i hariç tutmak için geldim ve birçok güzel cevabı okuduktan sonra find . -type f -print -o -path "*/node_modules" -prune... yerleşmiş joker karakteri kullanarak bu "node_modules" herhangi bir seviyede atlar; -printilk alternatifte kullanmak -type f -printsadece o parçayı yazdırır, bu nedenle "node_modules" dizinleri listelenmez. (aynı zamanda ters olabilir: find . -path "*/node_modules" -prune -o -type f -print)
Stephen P

orada ne var? Hariç tutmak istediğiniz tam dosya nedir. Ypu, joker karakter olarak kullanılıyor mu?
Siju V

1
@StephenP, bunu işaret ettiğiniz için teşekkürler; Kullanmak ./node_modulesve kullanmak arasındaki farkı öğrendim */node_modules. Benim durumumda, node_modulessadece aramayı başlattığım dizinde (ve bu node_modulesdizinin altında ) bulunduğu yerde, başka find . -type f -print -o -path "./node_modules" -prune bir node_modulesdizinin altında bir dizin olmayacağı için kullanabilirim .
bmacnaughton

1
@SijuV - aradığım dizinde bir node_modulesalt dizin vardı, ancak kendi node_modules'leri olan alt dizinler de vardı ... kullanarak ./node_modulessadece node_modulesgeçerli dizinin altındaki alt dizinle eşleşir ve budaır. ; kullanarak */node_modules, çünkü her derinlikte eşleşir ve kuru erik dizini *bir şekilde glob herhangi lider yol öneki maçları gibi ./test5/main/node_modules, sadece ./önek. *Bir joker, ama bir topak olarak değil bir regex olarak.
Stephen P

5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

Bu işe yaramaz. find ~/Projects -name '*.js' -\! -name 'node_modules' -prunehala node_modulesyolundaki dosyaları
açıyor

1
@mpen, stackoverflow.com/questions/4210042/… 'dan istediğiniz sözdiziminin olduğunu öğrendim find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print. Bu yolun adı, dizini yazdıracaksa bulduğu öğenin tam olarak aynı olması gerekir.
PatS

4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

gibi çalışıyor gibi görünüyor

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

ve IMO'yu hatırlamak daha kolaydır.


4

TLDR:-path <excluded_path> -prune -o seçeneği kullanarak kök dizinlerinizi anlayın ve aramanızı oradan özelleştirin . Sondaki noktayı dahil etme/Dışlanan yolun sonuna .

Misal:

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


Etkili bir şekilde kullanmak için findben dosya sistemi dizin yapısı hakkında iyi bir anlayış olması gerektiğine inanıyorum. Ev bilgisayarımda çoklu TB sabit disklerim var, içeriğin yaklaşık yarısı rsnapshot(yani rsync) kullanılarak yedekleniyor . Fiziksel olarak bağımsız (yinelenen) bir sürücüye yedeklense de, sistem root ( /) dizinimin altına monte edilir /mnt/Backups/rsnapshot_backups/::

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

/mnt/Backups/rsnapshot_backups/Dizin şu anda 60M dosya ve klasörler ~ ile ~ 2.9 TB kaplar; basitçe bu içerikleri taramak zaman alır:

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

Bu nedenle, /(kök) bölümümde bir dosya aramam gerektiğinde, yedekler bölümümü geçerek (mümkünse kaçınmalıyım) uğraşmam gerekir.


ÖRNEKLER

Bu iş parçacığında önerilen çeşitli yaklaşımlar arasında ( find. Komutunda bir dizin nasıl hariç tutulur), kabul edilen yanıtı kullanan aramaların çok daha hızlı olduğunu görüyorum - uyarılar.

Çözüm 1

Diyelim ki sistem dosyasını bulmak istiyorum libname-server-2.a, ancak rsnapshotyedeklemelerimi aramak istemiyorum . Hızlı bir sistem dosyasını bulmak için, yol hariç kullanmak /mnt(yani kullanım /mntdeğil /mnt/, ya /mnt/Backups, ya ...):

## 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!

... bu dosyayı birkaç saniye içinde bulur, ancak bu işlem çok daha uzun sürer (tüm "hariç tutulan" dizinlerde yineleniyor gibi görünür):

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

Çözüm 2

Bu konuda sunulan diğer çözüm ( SO # 4210042 ) de kötü bir performans sergiliyor:

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

ÖZET | SONUÇLAR

" Çözüm 1 " de gösterilen yaklaşımı kullanın

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

yani

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

izleyenleri /hariç tutulan yola eklediğinizde, findkomut daha sonra (tüm bu) /mnt/*dizinlere özyineli olarak girer - ki bu durumda, /mnt/Backups/rsnapshot_backups/*alt dizinler nedeniyle ek olarak aramak için ~ 2.9 TB dosya içerir! Bir iz ekleyemediğinizde /, arama neredeyse anında (saniyeler içinde) tamamlanmalıdır.

"Çözüm 2" ( ... -not -path <exclude path> ...) de, hariç tutulan dizinler arasında özyineli olarak arama yapıyor gibi görünüyor - hariç tutulan eşleşmeleri döndürmüyor, ancak bu arama süresini gereksiz yere tüketiyor.


Bu rsnapshotyedekler içinde arama :

Saatlik / günlük / haftalık / aylık rsnapshotyedeklemelerimden birinde dosya bulmak için ):

$ 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)

Yuvalanmış bir dizini hariç tutma:

Burada, örneğin /mnt/Vancouver/projects/ie/claws/data/*arama yaparken iç içe bir dizini hariç tutmak istiyorum /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

Kenara:-print Komutun sonuna eklemek , hariç tutulan dizinin çıktısını bastırır:

$ 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

Bu yavaşlatır dosyaların boyutu değil find, bu kadar dizin girişlerinin sayısı o incelemek gerekir. Bu nedenle, çok sayıda küçük dosyanız varsa (özellikle hepsi birden çok bağlıysa!) Bir avuç çok gigabayt dosyanızdan daha kötüdür.
Toby Speight

@TobySpeight: iyi bir nokta. Birçok dosya içeren ölçeği belirtmek için arama alanı boyutundan bahsetmiştim. Kök (/) ile sudo ls -R / | wc -l~ 76.5M dosyaları arasında hızlı arama (çoğu "yapılandırma dışı" sistem dosyaları dışında yedeklenir); /mnt/Vancouver/ile ls -R | wc -l~ 2.35M dosyaları belirtir; /home/victoria/0.668M dosya içerir.
Victoria Stuart

4

Ayrıca, aramanıza bazı dosyaları / dizinleri dahil etmek / hariç tutmak için normal ifadeleri aşağıdaki gibi bir şey kullanarak da kullanabilirsiniz:

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

Bu size yalnızca js, vue, css vb. Dosyaları verir ancak node_modulesve vendorklasörlerindeki tüm dosyaları hariç tutar .


3

findDosyaların bir listesini sağlamak için kullanıyordum xgettextve belirli bir dizini ve içeriğini atlamak istedim. -pathKombine ile birçok permütasyon denedim -pruneama tamamen istediğim dizini hariç tutamadım.

Yoksayılmasını istediğim dizinin içeriğini görmezden gelebilmeme rağmen find, dizinin kendisini sonuçlardan biri olarak döndürdü.xgettext olarak çökmeye oldu (dizinleri kabul etmiyor; sadece dosyalar).

Benim çözüm sadece grep -vsonuçlarda istemediğim dizini atlamak için kullanmak oldu:

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

Bunun find% 100 işe yarayacağına dair bir argüman olup olmadığı kesin olarak söyleyemem. Kullanılması grepbazı baş ağrısı sonra hızlı ve kolay bir çözüm oldu.


3

Ubuntu'da önceki yanıtların hiçbiri iyi değil. Bunu dene:

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

Bu bulduk burada


100'den fazla puan içeren cevapların Ubuntu üzerinde çalışmaması için hiçbir neden göremiyorum.
Axel Beckert

hadi görelim mi? belki hepsini denediğim için?
sixro

find, tüm Linux dağıtımlarında aynı uygulama olan GNU Projesi'ndeki her yerde aynıdır. Tek fark sürümler olabilir. Ancak son on yıldaki değişiklikler, belki de izin eşleşmesi dışında, bu kadar invaziv değildi.
Axel Beckert

3

Bu Mac'te benim için uygundur:

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

Eklenen arama adını hariç tutar vendorve yönlendirir .app/cachephp


'* .Php' çevresine tek tırnak işareti koyarsanız, aradığınızı bulamazsınız.
Br. Fatura

3

UNIX'in eski sürümlerinde -path veya -not kullanamayanlarınız için

SunOS 5.10 bash 3.2 ve SunOS 5.11 bash 4.4 üzerinde test edilmiştir

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

Belirtilen dizinden daha fazla iletilebilir.
MUY Belçika

2

nasıl kullanılır-buda-bul-in-sh seçeneği , Laurence Gonsalves'in nasıl -pruneçalıştığı konusunda mükemmel bir cevaptır .

Ve işte genel çözüm:

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

/path/to/seach/Birden çok kez yazmaktan kaçınmak için find, bir pushd .. popdçifti sarın .

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

1
Gönderen stackoverflow.com/questions/4210042/... , ben kullanılan sözdizimi öğrendim -patho kadar dizin yazdırmak olsaydı bulmak örneğin yazdırmak istiyorum, bu ismi aynı olmalıdır find . -path ./.git -prune -o -printveya find $HOME/foo -path $HOME/foo/.git -prune -o -print cevapların bazıları sadece söylemek -path somedirne yazık ki yararlı olacak kadar kesin değil.
PatS

2

Ihtiyacım ne için landscape.jpg, kökten başlayarak ve /vardizindeki arama hariç tüm sunucu bulma, böyle çalıştı :

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

find / -maxdepth 1 -type diçindeki tüm d dizinleri listeler/

grep -v /var / var 'i listeden hariç tutar

xargs -I '{}' find '{}' -name landscape.jpgfindlisteden her dizin / sonuç gibi herhangi bir komutu yürütün


Bir saniye, /henüz hariç tutulmadı. İhtiyacınız olabilir sed 1d.
Simba

2

Aşağıdaki komutlar çalışır:

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

Bulmayla ilgili bir sorununuz varsa -D tree, ifade analizi bilgilerini görüntüleme seçeneğini kullanın.

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

Veya, -D alltüm yürütme bilgilerini görmek için.

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

1

C kaynak dosyalarında işlev adını * .o ve * .swp ve * (normal dosya değil) hariç tut ve bu komutla dir çıktısını hariç tuttum:

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

1

execEylemi fordöngüden daha iyi kullanın :

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

exec ... '{}' ... '{}' \;Parantez yerine her eşleştirme dosyası için bir kez çalıştırılacaktır '{}'geçerli dosya adı ile.

Parantezlerin kabuk komut dosyası noktalama işareti olarak yorumlanmasını önlemek için tek tırnak içine alındığına dikkat edin * .


notlar

* Kılavuz find (GNU findutils) 4.4.2sayfasının ÖRNEKLER bölümünden


1
Çok eski bir soru, ama yine de iyileştirmeler için oda. Benzer bir sorunu çözmeye çalışırken şans eseri buldum ve cevapların hiçbiri tatmin edici değildi.
Alberto

Kullandığım execgenellikle aksiyon ve çok yararlı buluyorum. Ben genellikle {}dosya yollarında veren boşluklar arasında tırnak ekleyin "{}".
Ludovic Kuty

@lkuty Yorumunuzu yansıtacak şekilde yazımı düzenlemek üzereydim, ancak hızlı bir testten sonra (alıntı yapmadan, {}adlarında beyaz boşluklu dosyalar için çalışır) ve man sayfalarına bir bakıştan sonra, alıntı yapmak sadece kaçınmak için gerekli görünüyor Kabuk betiği noktalama işareti olarak yanlış yorumlanmaları gerekir. Bu durumda, tek tırnak kullanırsınız:'{}'
Alberto

Sanırım bunu yapmak için kullanmalıydım cpya mvda rm. Kontrol edeceğim
Ludovic Kuty

1

Yukarıdaki komutu denedim, ancak "-prune" kullananların hiçbiri benim için çalışmıyor. Sonunda bunu aşağıdaki komutla denedim:

find . \( -name "*" \) -prune -a ! -name "directory"
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.