Sh içinde 'find' seçeneği '-prune' seçeneği nasıl kullanılır?


219

Verilen örneği tam olarak anlamıyorum, man findkimse bana bazı örnekler ve açıklamalar verebilir mi? İçinde düzenli ifadeyi birleştirebilir miyim?


Daha ayrıntılı soru şudur:

Bir changeallarayüze sahip bir kabuk betiği yazın changeall [-r|-R] "string1" "string2". Bu bir sonek ile tüm dosyaları bulacaksınız .h, .C, .cc, veya .cppgeçtiği her yerde değiştirmek ve string1için string2. -ryalnızca geçerli dizinde kalma veya alt dizinleri dahil etme seçeneğidir.

NOT:

  1. Özyinelemeli olmayan durumlarda, lsizin VERİLMEZ, sadece findve kullanabiliriz sed.
  2. Denedim find -depthama desteklenmedi. Bu yüzden -pruneyardım edip edemeyeceğini merak ediyordum , ancak örneği anlayamadım man find.

EDIT2: Görev yapıyordum, ayrıntılı olarak soru sormadım çünkü kendim bitirmek istiyorum. Zaten yaptığım ve teslim ettiğimden, şimdi tüm soruyu söyleyebilirim. Ayrıca, ödevi kullanmadan bitirmeyi başardım -prune, ancak yine de öğrenmek istiyorum.

Yanıtlar:


438

Kafa karıştırıcı bulduğum şey -prune, bunun bir eylem (örneğin -print), bir test (değil) olduğudur -name. "Yapılacaklar" listesini değiştirir, ancak her zaman true değerini döndürür .

Kullanmak için genel örüntü -pruneşudur:

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

Hemen hemen her zaman istediğiniz -ohemen sonra (mantıksal OR) -pruneilk testin bir parçası (kadar ve dahil çünkü -prune) dönecektir yanlış Size gerçekten istediğiniz şeyler için (yani: Eğer şeyler yapamaz dışarı budamak istiyorum).

İşte bir örnek:

find . -name .snapshot -prune -o -name '*.foo' -print

Bu, ".snapshot" dizinleri altında olmayan "* .foo" dosyalarını bulur. Bu örnekte, -name .snapshotyapar [conditions to prune]ve -name '*.foo' -printbir [your usual conditions]ve [actions to perform].

Önemli notlar :

  1. Yapmak istediğiniz tek şey sonuçları yazdırmaksa, -printeylemi dışarıda bırakmak için kullanılabilir . Bunu kullanırken genellikle bunu yapmak istemezsiniz -prune.

    Bulmanın varsayılan davranışı , sonunda (ironik olarak) dışında bir eylem yoksa tüm ifadeyi -printeylemle "ve" işaretlemektir -prune. Bu şunu yazıyor demektir:

    find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS

    bunu yazmakla eşdeğerdir:

    find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS

    bu da budama yaptığınız dizinin adını yazdıracağı anlamına gelir, bu genellikle istediğiniz şey değildir. Bunun yerine, -printeğer istediğiniz buysa eylemi açıkça belirtmek daha iyidir :

    find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
  2. Senin "olağan durum" da Sen meyve koşulla eşleşen dosyaları maç olur, bu dosyalar olacak değil çıktıda yer alması. Bunu düzeltmenin yolu -type d, kuru erik durumunuza bir yüklem eklemektir .

    Örneğin, ile başlayan herhangi bir dizini bulaştırmak istediğimizi varsayalım .git(bu itirafla biraz anlaşılır - normalde sadece tam olarak adlandırılan şeyi kaldırmanız gerekir .git), ancak bunun dışındaki dosyalar da dahil olmak üzere tüm dosyaları görmek istedim .gitignore. Bunu deneyebilirsiniz:

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS

    Bu , çıktıya dahil edilmez.gitignore . İşte sabit sürüm:

    find . -name '.git*' -type d -prune -o -type f -print       # DO THIS

Ek ipucu: için GNU sürümünü kullanıyorsanız find, için texinfo sayfasının kılavuzundan finddaha ayrıntılı bir açıklaması vardır (çoğu GNU yardımcı programı için geçerlidir).


6
metninizde% 100 açık değildir (ancak yalnızca '* .foo' yazdırdığınızda çakışmaz), ancak -prune bölümü de ".snapshot" adlı hiçbir şeyi (yalnızca dizinleri değil) yazdırmaz. yani, -pruneyalnızca dizinler üzerinde çalışmaz (dizinler için de, bu koşulla eşleşen dizinlerin, yani burada buna uyan dizinlerin girilmesini engeller -name .snapshot).
— Olivier Dulac

12
ve güzel bir açıklama (ve özellikle önemli not) için + 1'leyin. Bunu bulucu geliştiricilere göndermelisiniz (man sayfası normal insanlar için "kuru erik" i açıklamıyor ^
— Olivier Dulac

2
@OlivierDulac Bu, saklamak istediğiniz dosyaları potansiyel olarak sıyırma konusunda çok iyi bir nokta. Bunu açıklığa kavuşturmak için cevabı güncelledim. bu arada buna -prunesebep olan aslında kendisi değildir . Sorun şu ki veya operatörü "kısa devreler" ve veya daha düşük önceliğe sahiptir. Sonuçta adlı bir dosya varsa yani .snapshotkarşılaşıldığında ilk maç olacak -name, -pruneo zaman hiçbir şey yapacağız (ama gerçek dönüş) ve onun sol argüman doğruydu çünkü o zaman ya geri döner doğrudur. Eylem (örneğin -print:) ikinci argümanının bir parçasıdır, bu yüzden asla yürütme şansı yoktur.
— Laurence Gonsalves

3
Ben neden ihtiyaç 1 nihayet öğrendim -printsonunda ben şimdi durdurma ekleyerek yapabilirsiniz, \! -path <pattern>ek olarak-prune
— Sefil Değişken

6
"-O" ifadesinin "-or" kısaltması olduğunu (POSIX uyumlu olmasa da) daha net okuduğunu unutmayın.
— yoyo

27

Normalde linux'da bir şeyler yapmanın doğal yolu ve düşünce şeklimiz soldan sağa doğrudur.
Böylece ilk aradığınızı yazın ve yazın:

find / -name "*.php"

O zaman enter tuşuna basarsınız ve istemediğiniz dizinlerden çok fazla dosya aldığınızı fark edersiniz. Takılı sürücülerinizi aramaktan kaçınmak için medyayı hariç tutalım.
Şimdi bir önceki komuta aşağıdakileri eklemeniz yeterlidir:

-print -o -path '/media' -prune

bu yüzden son komut:

find / -name "*.php" -print -o -path '/media' -prune

............... | <--- Dahil et ---> | .................... | <- -------- Hariç Tut ---------> |

Bence bu yapı çok daha kolay ve doğru yaklaşımla ilişkili


3
Bunun verimli olmasını beklemezdim - bu erikten önce sol cümleyi değerlendireceğini düşünürdüm, ama şaşırtıcı bir şekilde hızlı bir test find, önce -prunecümleyi işlemek için yeterince akıllı olduğunu gösteriyor . Hmmm, ilginç.
— artfulrobot

GNU'yu kullanmanın neredeyse on yılında olduğunu hiç düşünmemiştim! Bunun için teşekkür ederim! Bundan böyle düşünme şeklim kesinlikle değişecek -prune.
— Felipe Alvarez

3
@artfulrobot Gerçekten önce işliyor mu? /mediaGirdiğini düşünürdüm , çağrılmadığını fark eder *.phpve sonra içeride olup olmadığını kontrol eder, /mediaolduğunu görür ve bu nedenle tüm alt ağacı atlar. Hala soldan sağa, her iki kontrol de çakışmadığı sürece hiçbir fark yaratmıyor.
— phk

26

Bazılarının söylediği gibi -prune'un herhangi bir dizine inmesini önlemediğini unutmayın . Uygulandığı testle eşleşen dizinlere inmeyi önler. Belki bazı örnekler yardımcı olacaktır (normal ifade örneği için aşağıya bakınız). Bunun çok uzun olduğu için üzgünüm.

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

ayrıca "./dir1/scripts/test dokunma" (yani, bir "test" dosyasını var ve bu Subdir basılmış değil dir,), bu tarafından printd almazsınız find . -name test -prune -o -print: IOW, -prunebir eylem olduğunu da dosyalar üzerinde çalışır
— Olivier Dulac

10

Diğer cevaplarda verilen tavsiyelere ek olarak (cevap oluşturmak için temsilcim yok) ...

-pruneDiğer ifadelerle birleştirilirken , hangi ifadelerin kullanıldığına bağlı olarak küçük bir davranış farkı vardır.

@Laurence Gonsalves 'örneği ".snapshot" dizinleri altında olmayan "* .foo" dosyalarını bulacaktır: -

find . -name .snapshot -prune -o -name '*.foo' -print

Ancak, bu biraz farklı kısa el, belki de yanlışlıkla, .snapshotdizini (ve herhangi bir iç içe .snapshot dizinlerini) listeler: -

find . -name .snapshot -prune -o -name '*.foo'

Nedeni (sistemimdeki kılavuza göre): -

Verilen ifade -exec, -ls, -ok veya -print gibi herhangi bir primer içermiyorsa, verilen ifade etkili bir şekilde aşağıdakilerle değiştirilir:

(verilen_ifade) -baskı

Yani, ikinci örnek aşağıdakileri girmeye eşdeğerdir, böylece terimlerin gruplanmasını değiştirir: -

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

Bu en azından Solaris 5.10'da görülmüştür. Yaklaşık 10 yıldır * nix'in çeşitli tatlarını kullandıktan sonra, bunun son zamanlarda bunun nedenini araştırdım.


Birlikte -pruneolan ve olmayan kullanım arasındaki farka dikkat çektiğiniz için teşekkür ederiz -print!
— mcw

3

Kuru erik, herhangi bir dizin anahtarında yinelenmez.

Man sayfasından

-Depth verilmezse true; dosya bir dizinse, dosyaya inmeyin. -Depth verilirse false; etkisi yok.

Temel olarak herhangi bir alt dizine girmeyecektir.

Bu örneği ele alalım:

Aşağıdaki dizinlere sahipsiniz

  • / Home / dnm2
  • / Home / dnm2 / dnm2

Eğer koşarsan find -name test2:

Her iki dizini de döndürür

Eğer koşarsan find -name test2 -prune:

/ Home / test2 / test2 öğesini bulmak için / home / test2'ye inmeyeceğinden yalnızca / home / test2 döndürecektir.


% 100 doğru değil: "koşul eşleştirilirken budama yapın ve eğer bir dizinse, yapılacaklar listesinden çıkarın, yani girmeyin." -prune dosyalar üzerinde de çalışır.
— Olivier Dulac

2

Ben bu konuda uzman değilim (ve bu sayfa http://mywiki.wooledge.org/UsingFind ile birlikte çok yardımcı oldu )

Sadece farkedilen dizeden / yoldan tam olarak eşleşen-path bir yol için ( bu örneklerde) tüm taban adlarıyla eşleşir.find.-name

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

bloklar mevcut dizinde .git dizin ( daki bulgu olarak . )

find . -name .git  -prune -o -name file  -print

tüm .git alt dizinlerini yinelemeli olarak engeller.

Not ./ son derece önemlidir !! -pathBağlantılı bir yolla eşleşmeli . ya da onunla eşleşirseniz (ya da ' -o') eşleşirse, muhtemelen budama yapılmazsa, bulduktan hemen sonra gelen her şeyle eşleşmelidir ! Naif olarak bunun farkında değildim ve aynı alt adıyla tüm alt dizini budamak istemediğinizde harika olduğunda -path'i kullanmamı sağladı: D


find bla/Yapmanız gerektiğini söylüyorsa, o zaman bla/-path .git'e ihtiyacınız olacak (ya *da ön tarafa atılmışsa , bunun yerine -name gibi davranacaktır)
— sabgenton

1

Dir kendisi dahil her şeyi göster, ancak uzun sıkıcı içeriği değil:

find . -print -name dir -prune

0

Burada tüm iyi cevapları okursanız, şimdi anladığım kadarıyla aşağıdakilerin hepsi aynı sonuçları döndürüyor:

find . -path ./dir1\*  -prune -o -print

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

find . -path ./dir1\*  -o -print
#look no prune at all!

Ama sonuncusu hala dir1'deki her şeyi araştırdığı için çok daha uzun sürecek. Asıl soru, -oristenmeyen sonuçların gerçekten aramadan nasıl çıkarılacağıdır.

Bu yüzden budamak, geçmiş maçları iyi değil ama bitti olarak işaretlemek anlamına geliyor ...

http://www.gnu.org/software/findutils/manual/html_mono/find.html "Ancak bu '-prune' eyleminin etkisinden kaynaklanmıyor (sadece daha fazla inişi önlüyor, emin değil Bunun yerine, bu etki '-o' kullanımından kaynaklanmaktadır. “veya” koşulunun sol tarafı ./src/emacs için başarılı olduğundan, sağ- bu dosya için hiç bir tarafı ('-print') içermez. "


0

finddosyaların bir listesini oluşturur. Her birine verdiğiniz yüklemi uygular ve geçenleri verir.

-pruneSonuçlardan dışlama anlamına gelen bu fikir benim için gerçekten kafa karıştırıcıydı. Bir dosyayı kurulamadan hariç tutabilirsiniz:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

Tüm -pruneyapmanız gereken, aramanın davranışını değiştirmek. Geçerli eşleşme bir dizinse, "hey find, yeni eşlediğiniz dosya, içine inmeyin " der . Yalnızca bu ağacı (dosyanın kendisini değil) aranacak dosyalar listesinden kaldırır.

Adı belirtilmelidir -dont-descend.


0

Birkaç cevap var; bazıları biraz fazla teori ağırlıklı. Neden bir kez erik ihtiyacım olduğunu bırakacağım, bu yüzden belki de ilk ihtiyaç / örnek açıklama biri için yararlıdır :)

Sorun

Her biri kendi node_modulesdizin beklendiği gibi olan yaklaşık 20 düğüm dizinleri olan bir klasör vardı .

Herhangi bir projeye girdikten sonra, her birini görürsünüz ../node_modules/module. Ama nasıl olduğunu biliyorsun. Hemen hemen her modülün bağımlılıkları vardır, bu yüzden baktığınız şey daha çokprojectN/node_modules/moduleX/node_modules/moduleZ...

Ben bağımlılığı bağımlılığı ile bir liste ile boğmak istemiyordu ...

Her projeden istediğim ana / ilk node_modules dizini farklı bir derinlikte olduğu için -d n/ 'yi bilmek -depth nbana yardımcı olmazdı:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

İlkinde biten yolların ilk listesini nasıl alabilirim ve bir node_modulessonraki projeye nasıl geçebilirim?

Giriş -prune

Eklediğinizde -prune, yine de standart bir yinelemeli aramaya sahip olursunuz. Her "yol" analiz edilir ve her buluntu tükürür ve findiyi bir adam gibi kazmaya devam eder. Ama node_modulesistemediğim şey için aşağı iniyor .

Yani, fark bu farklı yolların herhangi, yani -pruneedecek findo öğeyi bulduğunuz zaman belirli bir cadde olduğunu ileri aşağı kazma durdurmak için. Benim durumumda, node_modulesklasör.

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.