Alt dizinlerdeki dosyaları nasıl bulabilir ve tek bir komutta dosya adına göre nasıl sıralayabilirim?


9

Aşağıdakileri kullanarak normal bulmanın sonucu find . ! -path "./build*" -name "*.txt":

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

ve şuna göre sıralandığında sort -n:

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

ancak istenen çıktı:

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

yani, çıktı yalnızca dosya adına göre sıralanır , ancak klasör bilgileri çıktının bir parçası olarak korunmalıdır.

Düzenleme : Alt dizin yapısı birden fazla düzey içerebileceğinden örneği daha karmaşık hale getirin.


2
SO hakkında sorduğum bu soruya bakın: stackoverflow.com/questions/3222810/…
camh

@camh - mümkünse yalnızca unix komutlarını kullanmak istiyorum. Her halükarda, sorum hemen hemen size ait. Bu konuya en iyi çözümü aktarabilir misiniz (yine de orijinaline bir bağlantı tutun), böylece çözüm olarak işaretleyebilir miyim?
8'de unode

@Shawn, yorumumda önerdiğim değişiklikleri yaparsa ( -printfbunun yerine kullanın awk), bunun en iyi çözüm olduğunu düşünüyorum. Bu yöntemi kullanmak için orijinal uygulamamı yeniden çalıştım.
camh

Yanıtlar:


9

Son alana göre sıralamanız gerekir ( /alan ayırıcı olarak düşünülür ). Ne yazık ki, alanların sayısı değiştiğinde bunu yapabilen bir araç düşünemiyorum (yalnızca sort -knegatif değerler alabilirse).

Bunun üstesinden gelmek için bir dekore-sırala-dekore etmelisiniz. Yani, dosya adını alın ve başında bir alan ayırıcısı takip edin, ardından bir sıralama yapın, ardından ilk sütunu ve alan ayırıcıyı kaldırın.

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

Bu awkkomut diyor alan ayırıcı FS olarak ayarlanır /; bu alanları okuma şeklini etkiler. Çıkış alanı ayırıcı OFS da ayarlanır /; bu kayıtları yazdırma biçimini etkiler. Bir sonraki ifade, son sütunun ( NFkayıttaki alanların sayısıdır, bu nedenle son alanın dizini de olur) ve tüm kaydın ( $0tüm kayıt) yazdırılmasını söylüyor ; aralarında OFS yazdıracaktır. Sonra listesi sorttedavi, ed /alan ayırıcı olarak - biz ilk kaydındaki dosya adı beri, o kadar sıralanır. Daha sonra, cutyalnızca alan 2'yi sonuna kadar yazdırır ve yine /alan ayırıcı olarak davranır.


3
Bul (1) ile olduğu için, awk bölümünü atlayabilir ve kullanabilirsiniz-printf '%f/%p\n'
camh

aslında kurulumumuz biraz daha karmaşıktır. Değişken alt dizin derinliklerini içerir. Soruyu bu gerçeği yansıtacak şekilde düzenledi. İlk başta bunu eklemediğim için özür dilerim.
28'de unode

1
@Unode: Shawn'un çözümü değişken derinliği gayet iyi idare ediyor, bu sorunun kanonik çözümü (küçük varyasyonlara kadar).
Gilles 'SO- kötü olmayı kes'

4

'-Printf' dosyalarını ad ve yol çıktısı almak, ada göre sıralamak ve son adımda adı kesmek için kullanırdım. '###' sadece kesmeye yardımcı olan bir işaretleyicidir.

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

% f dosya adını,% p tüm yolu yazdırır.

Tek bir satıra almak için find komutunu basitleştirdim, elbette ! -path "./build*"parçayı terk edersiniz .


3

Zsh ≥4.3.10'da:

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txt*.txtgeçerli dizindeki ve alt dizinlerindeki özyinelemeli olarak eşleşir .
  • ~build* metni build*(gibi ! -path './build*') ile başlayan eşleşmeleri hariç tutar . (Önce ihtiyacınız var setopt extended_glob.)
  • (oe\''…'\')bir sıralama glob niteleyicidir . REPLY=…döndürülecek dizeden sıralanacak dizeyi oluşturur.
  • ${REPLY:t}olan basename yolunun ( “kuyruk”).

Birleştirilmiş sihir. İlginç ama biz sh sözdizimi ile sınırlıyız. +1
unode
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.