İki veya daha fazla dosya içeren dizinler


11

Geçerli dizinin alt dizinini (alt dizin) 2 veya daha fazla normal dosya içeren bulmak istiyorum.

2'den az dosya içeren dizinlerle ilgilenmiyorum, ne de sadece alt dizinleri içeren dizinlerle.

Yanıtlar:


12

İşte GNU findve dayalı tamamen farklı bir yaklaşım uniq. Bu, bulunan her dizin için dosyaları sayan bir kabuk komutunun yürütülmesine dayalı cevaplardan çok daha hızlı ve CPU dostudur.

find . -type f -printf '%h\n' | sort | uniq -d

findKomut hiyerarşisinde tüm dosyaların dizinini yazdırır ve uniqsadece iki kez en az görünen dizinleri görüntüler.


2
Çıktısını ayrıştırmamalısınız find. Bu durumda, GNU find, geçerli yerel ayarda yazdırılamayan karakterlere sahip dizinlerin adlarını değiştirir (C yerel ayarındaki "ä" gibi). Ayrıca bkz. Unix.stackexchange.com/questions/321697/…
Kusalananda

4
@Kusalananda, çıktı bir tty'ye gitmediğinde değil. Burada, tek sorun kullanarak kullanarak düzeltebileceğiniz yeni satır karakterleri-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
Stéphane Chazelas

6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

Bu işlem, geçerli dizindeki veya altındaki tüm adları bulur ve ardından dizin adı olmayan tüm adları filtreler.

Kalan dizin adları bu kısa komut dosyasına verilecektir:

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

Bu komut dosyası, ilk komut satırı bağımsız değişkeni (from find) olarak verilen dizindeki normal dosya sayısını (sembolik bağlantıları atlayarak) sayar . Koddaki son komut, sayının 2 veya daha yüksek olup olmadığını görmek için bir sınamadır. Bu testin sonucu, komut dosyasının dönüş değeridir (çıkış durumu).

Sınama başarılı olursa, dizinin yolunun yazdırılmasına -printneden olur find.

Gizli dosyaları da (adları bir nokta ile başlayan dosyalar) dikkate almak için sh -ckomut dosyasını

for n in "$1"/*; do

için

for n in "$1"/* "$1"/.*; do

Test yapmak:

$ tree
.
`-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   `-- c
    `-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   `-- file-2
        `-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb

Çözümünüz nokta ile başlayan bir ada sahip dosyaları saymaz. Herhangi bir dosya içermeyen dizinlerdeki hata mesajlarından kaçınmak için c = 0'ı da başlatmalısınız.
xhienne

@xhienne Gizli dosyaları düşündüm ve bu konuda bir not ekleyeceğim. [ "" -ge 2 ]Geçerli bir sınama olduğundan bir dizinde normal dosya yoksa hata yoktur .
Kusalananda

"Geçerli" yi nasıl tanımladığınızdan emin değilim. POSIX, arg1 değerinin bir tamsayı olmasını gerektirir. dash, bash --posixVe testtüm ekran 2 ile bir hata mesajı ve çıkış (yani "Bir hata oluştu")
xhienne

@xhienne Ah, mas'ın kshçalıştığı bir sistemi test ediyordum sh. Hemen değişiklik yapacaktır. Bana alay ettiğin için teşekkürler! :-)
Kusalananda

Ayrıca, [ -f ... ]sembolik bağlantıları dereferences. Soru yalnızca normal dosyaların sayılması gerektiğini belirttiğinden bunları ortadan kaldırmak için bir test eklemelisiniz.
xhienne

6

Yardımıyla Gilles cevabı üzerine SU bunun tersinin ve bazı modifikasyon, ihtiyacınız ne burada.

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

Dizin ağacı.

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file\012with\012multiple\012line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

Sonuç:

./test
./test/dir1
./test/dir2/dirb

Ben de ilk başta bu vardı, ama birden fazla alt dizin ve dosya içeren dizinler ile sorun olacak . Ayrıca yalnızca alt dizinleri içeren dizinleri ayıklamaz.
Kusalananda

Gerçekten çözmüyor. Hem bulur testve dir2(benim cevap bakınız) benim test kurulumunda dizinleri.
Kusalananda

Ancak örneğin İşleri ekleyebilir test/x1ve test/x2aynı zamanda dosyaları gibi ... $1ve $2için dizinleri olacak testve dizin özleyeceğiz.
Kusalananda

@Kusalananda Cevap verdiklerinizin dışında bir yol bulamadım, komutumun bir kısmını kendinizin tam kopyası olmayacak şekilde değiştirmeye çalıştım (yaptığınız gibi gizli dosyaları hariç tutmadım), özür dilerim.
αғsнιη

1
Merak etmeyin :-)
Kusalananda

3

Başka find+ wcyaklaşımı:

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print

  • path/currdir - geçerli dizininize giden yol

  • -maxdepth 1- yalnızca doğrudan alt alt klasörleri göz önünde bulundurun

  • ! -empty - boş alt klasörleri yoksay

  • ! -path "path/currdir" - geçerli dizin yolunu yoksay

  • count=$(find "$1" -maxdepth 1 -type f | wc -l)- countbulunan her alt klasör için dosya sayısı atanır

  • [ $count -ge 2 ] ... -print - 2 veya daha fazla normal dosya içeren alt klasör adı / yolu yazdı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.