POSIX bulmayı belirli derinlikle sınırla?


15

Son zamanlarda POSIX spesifikasyonlarınınfind-maxdepth birincil içermediğini fark ettim .

Kendisine aşina olmayanlar için, -maxdepthbirincil olanın amacı kaç seviyenin derinliklerine findineceğini kısıtlamaktır . -maxdepth 0sonuçlar yalnızca komut satırı değişkenleri işlenen; -maxdepth 1yalnızca doğrudan komut satırı bağımsız değişkenleri vb. içindeki sonuçları işler.

-maxdepthYalnızca POSIX tarafından belirtilen seçenekleri ve araçları kullanarak POSIX dışı birincil öğeye eşdeğer davranışı nasıl alabilirim ?

(Not: Tabii ki -maxdepth 0sadece -pruneilk işlenen olarak kullanarak eşdeğerini elde edebilirim , ancak bu diğer derinliklere uzanmaz.)


@StevenPenny, FreeBSD -depth -2, -depth 1... yaklaşımı GNU'lardan daha iyi görülebilir -maxdepth/-mindepth
Stéphane Chazelas

@ StéphaneChazelas her iki durumda da - POSIX buluntusunun biri veya diğeri olmalıdır; başka sakat
Steven Penny

1
En azından -maxdepth/ -mindepthiçin makul alternatifler var ( -pathPOSIX'e yeni eklenen bir ek not ). -timexyVeya -mtime -3m(veya -mmin -3) alternatifleri çok daha hantaldır. Bazılarının güvenilir bir alternatifi var -execdir/ -deleteyok.
Stéphane Chazelas

2
@StevenPenny, austingroupbugs.net adresinden bir bilet eklemek için istekte bulunun . Güçlü bir gerekçe olduğunda şeylerin bir sponsora ihtiyaç duyulmadan eklendiğini gördüm. Muhtemelen daha iyi bir eylem, ilk önce birçok uygulamanın eklemesini sağlamaktır, böylece POSIX, genellikle daha az çekişmeli olanı belirtmek zorunda kalacaktır.
Stéphane Chazelas

@ StéphaneChazelas benim durumumda sadece dosyaları doğrudan adlandırıyorum, ama teşekkür ederim; Tekrar gelirse bilet verebilirim
Steven Penny

Yanıtlar:


7

-pathBelirli bir derinliği eşleştirmek ve orada budamak için kullanabilirsiniz . Örneğin

find . -path '*/*/*' -prune -o -type d -print

olarak MaxDepth 1 olacağını *maçları ., */*maçların ./dir1ve */*/*kibrit ./dir1/dir2budanır. Mutlak bir başlangıç dizini kullanırsanız, lider eklemem gerekiyor /için -pathde.


Hmmm, zor. Desenin /*sonundan sadece bir katman kaldırabilir , -ooperatörü çıkarabilir ve aynı sonucu elde edemez misiniz ?
Wildcard

Hayır, çünkü *maçlar /da öyle, bu yüzden dir ne yazık ki a/b/c/d/esığacaktı -path */*.
meuh

Ama a/b/c/d/easla ulaşılamazdı , çünkü -pruneuygulanır a/b...
Wildcard

1
Üzgünüm, bunu yanlış okudum -pruneve -okaldırıldım. Eğer -prunesorun devam ederse */*, maxdepth, örneğin tek bir dizin üzerinde bir düzeyde hiçbir şey eşleşmeyecek olmasıdır a.
meuh

11

@ meuh yaklaşımı verimsizdir çünkü -maxdepth 1yaklaşımı hala finddaha sonra onları görmezden gelmek için seviye 1'deki dizinlerin içeriğini okumasına izin verir . Bazı dizin adları, kullanıcının yerel ayarında geçerli karakterler oluşturmayan bayt dizileri içeriyorsa find(GNU dahil find) bazı uygulamalarla da düzgün çalışmaz ( farklı bir karakter kodlamasındaki dosya adları gibi).

find . \( -name . -o -prune \) -extra-conditions-and-actions

GNU'ları -maxdepth 1(veya FreeBSD'leri -depth -2) uygulamanın daha kanonik yoludur .

Genel olarak, dikkate almak istemediğiniz gibi -depth 1( -mindepth 1 -maxdepth 1) .(derinlik 0) istediğiniz ( ) ve daha da basit:

find . ! -name . -prune -extra-conditions-and-actions

Çünkü -maxdepth 2bu olur:

find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

Ve burada geçersiz karakter sorunlarıyla karşılaşıyorsunuz.

Örneğin, denilen Stéphaneancak é2000'lerin ortalarına kadar Batı Avrupa ve Amerika'da en yaygın olan iso8859-1 (latin1) karakter kümesinde (0xe9 bayt) kodlanmış bir dizininiz varsa , 0xe9 baytı bir UTF-8'de geçerli karakter. Yani, UTF-8 yerellerde, *(bazı joker finduygulamaları) Eşleşmeyecek Stéphaneolarak *0 veya daha fazla karakter ve karakter 0xe9 değildir.

$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith

My find(çıkış bir terminale gittiğinde) ?yukarıdaki gibi geçersiz 0xe9 baytını görüntüler . Bunun d St<0xe9>phane/Chazelasolmadığını görebilirsiniz prune.

Yaparak bunun etrafında çalışabilirsiniz:

LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

Ancak bunun tüm yerel ayarları findve çalıştırdığı herhangi bir uygulamayı ( -exectahminler gibi ) etkilediğini unutmayın .

$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith

Şimdi, gerçekten olsun -maxdepth 2ama UTF-8 düzgün şekilde kodlanmış ikinci Stéphane é nasıl ??UTF-8 kodlama UTF-8 kodlama 0xc3 0xa9 bayt (C yerel iki tanımlanmamış karakter olarak kabul edilir) olarak görüntülendiğini not C yerel ayarında yazdırılamaz karakterler.

Ve eğer bir -name '????????'ekleseydim, yanlış Stéphane (iso8859-1 ile kodlanmış olan) almış olurdum.

Bunun yerine rastgele yollara başvurmak için .şunları yaparsınız:

find some/dir/. ! -name . -prune ...

için -mindepth 1 -maxdepth 1:

find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...

için -maxdepth 2.

Yine de şunu yapardım:

(cd -P -- "$dir" && find . ...)

Birincisi, bu, yolları daha kısa hale getirir, bu da çok uzun veya arg listesinin çok uzun sorunlara yol açmasını daha az hale getirir, ancak aynı zamanda boğulma olacağı için findrastgele yol argümanlarını ( -fFreeBSD ile hariç) destekleyemeyen gerçeği geçici findolarak çözer. değerleri $dirgibi !ya -print...


-oOlumsuzlama ile kombinasyon oluşan bağımsız iki takımın çalıştırmak için ortak bir hiledir -condition/ ' -actionde find.

-action1Dosya toplantısında -condition1ve bağımsız -action2olarak dosya toplantısında çalıştırmak istiyorsanız -condition2, şunları yapamazsınız:

find . -condition1 -action1 -condition2 -action2

-action2Sadece her iki koşulu da karşılayan dosyalar için çalıştırılacağı gibi .

Nor:

find . -contition1 -action1 -o -condition2 -action2

Her iki koşulu -action2da karşılayan dosyalar için çalıştırılmaz .

find . \( ! -condition1 -o -action1 \) -condition2 -action2

her dosya \( ! -condition1 -o -action1 \)için true olarak çözüleceği gibi çalışır . Yani varsayar -action1bir eylem (gibidir -prune, -exec ... {} +her zaman döner) doğrudur . Bunun gibi eylemler yanlış-exec ... \; döndürülebilirse , zararsız olan ancak GNU veya veya gibi doğru olan başka bir yer eklemek isteyebilirsiniz (yine de yukarıdaki geçersiz karakterler ile ilgili sorunu not edin).-o -something-something-truefind-links +0-name '*'


1
Bir gün bir sürü Çince dosyayla karşılaşacağım ve yerel ve geçerli karakterler hakkında birçok cevabınızı okuduğum için çok mutlu olacağım. :)
Joker

2
@Wildcard, siz (ve hatta bir Çinli kişi) İngiliz, Fransızca ... dosya adlarıyla sorun yaşama olasılığı daha yüksektir, çünkü Çince dosya adları UTF-8'de alfabetik komut dosyalarının dosya adlarından daha sık kodlanır. genellikle nispeten yakın zamana kadar norm olan tek baytlık bir karakter kümesiyle karşılanabilir. Çince karakterleri kapsayacak başka çok baytlık karakter kümeleri de var, ancak bu karakter kümelerinin bir dizi kötü sorunu olduğu için Çinli insanların batılılardan daha erken UTF-8'e geçmesini beklerdim. Örnek için düzenlemeye de bakın.
Stéphane Chazelas

0

Birden fazla yol ararken (sadece .) derinliği sınırlamak için bir yol gerekli bir sorunla karşılaştı .

Örneğin:

$ find dir1 dir2 -name myfile -maxdepth 1

Bu beni -regex kullanarak alternatif bir yaklaşıma götürdü. Buradaki öz:

-regex '(<list of paths | delimited>)/<filename>'

Yani, yukarıdaki:

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/myfile' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/myfile' # MacOS BSD

Dosya adı olmadan:

$ find dir1 dir2 -name myfile -maxdepth 1 # GNU

-regex '(<list of paths | delimited>)/<anything that's not a slash>$'

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/[^/]*$' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/[^/]*$' # MacOS BSD

Son olarak, -maxdepth 2normal ifade değişiklikleri için:'(dir1|dir2)/([^/]*/){0,1}[^/]*$'


1
Bu soru yine de standart (POSIX'te olduğu gibi) bir çözüm ister. Ayrıca -maxdepthbirden çok arama yolu ile çalışır.
Kusalananda
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.