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.