Bir dizindeki dosyaları saymak için wc'ye borulamaya daha özlü bir alternatif var mı?


12

Eğer yaparsam ls -1 target_dir | wc -l, bir dizinde bir dizi dosya alırım. Bunu biraz hantal buluyorum. Daha zarif veya özlü bir yol var mı?


2
Wc için borulama yaparken "-1" gerekmez.
Steve

lszaten toplam sayıyı veriyor, peki ls -l | head -1? Daha kısa bir şey istiyorsanız bir takma ad yapın.
Daniel Wagner

2
@DanielWagner "total: nnn" çıktısı ls -l, dosya sayısını değil, dosyaların toplam boyutunu gösterir.
David Richerby

2
Unutmayın ls | wc -lherhangi bir dosya adları yeni satır içeriyorsa size yanlış sayısını verecektir.
chepner

Bu dosya sistemine bağlıdır ve bir dizindeki dizinleri + 2 sayar. Cevabın 2 ekstra vardır (kendini ve ebeveynini sayar). stat -c %h .ile aynı bilgileri verirls -ld . | cut -d" " -f 2
ctrl-alt-delor

Yanıtlar:


12

Bash 4+ varsayarsak (desteklenen herhangi bir Ubuntu sürümüne sahiptir):

num_files() (
    shopt -s nullglob
    cd -P -- "${1-.}" || return
    set -- *
    echo "$#"
)

Olarak adlandırın num_files [dir]. diristeğe bağlıdır, aksi takdirde geçerli dizini kullanır. Orijinal sürümünüz gizli dosyaları saymaz, bu nedenle de. Eğer isterseniz, daha shopt -s dotglobönce set -- *.

Orijinal örneğiniz sadece normal dosyaları değil, aynı zamanda dizinleri ve diğer cihazları da sayar - gerçekten sadece normal dosyaları (normal dosyalara bağlantılar dahil) istiyorsanız, bunları kontrol etmeniz gerekir:

num_files() (
    local count=0

    shopt -s nullglob
    cd -P -- "${1-.}" || return
    for file in *; do
        [[ -f $file ]] && let count++
    done
    echo "$count"
)

GNU bulmanız varsa, bunun gibi bir şey de bir seçenektir (bunun orijinal komutunuzun yapmadığı gizli dosyaları içerdiğini unutmayın):

num_files() {
    find "${1-.}" -maxdepth 1 -type f -printf x | wc -c
}

(değişiklik -typeiçin -xtypede düzenli dosyalara sembolik saymak istiyorsanız).


setÇok fazla dosya varsa başarısız olmaz mı? Bence xargsgenel durumda bu çalışması için kullanmak ve bazı toplama kodu gerekebilir .
l0b0

1
Ayrıca shopt -s dotglob, ile başlayan dosyaların .sayılmasını istiyorsanız
Digital Trauma

1
@ l0b0 setBu koşullar altında başarısız olacağını düşünmüyorum , çünkü aslında bir exec. Zekâ, benim sistemimde, getconf ARG_MAX262144 verir, ama eğer yaparsam test_arg_max() { set -- {1..262145}; echo $#; }; test_arg_max, mutlu bir şekilde 262145 yanıtlar.
kojiro

@DavidRicherby -maxdepthPOSIX değil.
Chris Down

4
@MichaelMartinez Açık kod yazmak, doğru kod yazmak yerine geçmez.
Chris Down

3

f=(target_dir/*);echo ${#f[*]}

adında boşluklar, yeni satırlar vb. olan dosyalar için düzgün çalışır.


bir bağlam sağlayabilir misin? Bu bir bash senaryosunda olmalı mı?
codecowboy

o olabilir. doğrudan kabuğa da koyabilirsiniz. bu sürüm geçerli dizini istediğinizi varsaydı; düzenledim, bu yüzden sorunuza daha yakın. temel olarak dizindeki tüm dosyaları içeren bir kabuk dizisi değişkeni yaratır, sonra o dizinin sayısını yazdırır. diziler içeren herhangi bir kabukta çalışmalıdır - bash, ksh, zsh, vb. - ama muhtemelen düz sh / ash / dash.
Aaron Davies

2

lsyalnızca bir terminale doğrudan çıktı verirse çok sütundur, "-1" seçeneğini kaldırabilirsiniz, wc"-l" seçeneğini kaldırabilir , yalnızca ilk değeri okuyabilirsiniz (tembel çözüm, legual kanıtlar için kullanılmaz, cezai soruşturmalar, kritik görev, taktik operasyonlar ..).

ls target | wc 

5
Yeni satırlar içeren dosya adları için bu başarısız olur.
l0b0

@Emmanuel wcÖnemsiz durumda bile dosya sayısını elde etmek için sonucunuzu ayrıştırmanız gerekecek , bu nasıl bir çözüm?
l0b0

@Emmanuel targetGenişletildiğinde tire ile başlayan bazı şeyler içeren bir glob ise başarısız olabilir . Örneğin, yeni bir dizin oluşturun, bu dizine girin ve yapın touch -- {1,2,3,-a}.txt && ls *|wc(Not: rm -- *.txtbu dosyaları silmek için kullanın .)
David Richerby

Bunu mu demek istediniz wc -l? Aksi takdirde, lsçıkışın satır, kelime ve bayt sayılarını alırsınız . David Richerby şöyle dedi: Tekrar ayrıştırmalısınız.
erik

@erik wcBeyniniz ilk argümanın satırsonu olduğunu biliyorsa, ayrıştırmanıza gerek kalmadan hiçbir argüman olmadan bahsediyorum .
Emmanuel

2

'S özlülük Eğer, ben sadece aliasing tavsiye (daha doğrusu adlarında yeni satırlarla, vb dosyaları ile ilgili kesin doğruluğu yerine) peşindeler wc -liçin lc( "hat sayısı"):

$ alias lc='wc -l'
$ ls target_dir|lc

Diğerlerinin de belirttiği gibi, bir -1seçeneğe ihtiyacınız yoktur ls, çünkü lsbir boruya yazarken otomatiktir . ( lsHer zaman sütun modunu kullanmak için takma ad eklemediyseniz. Daha önce gördüm, ancak çok sık değil.)

Bir lctakma ad genel olarak oldukça kullanışlıdır ve bu soru için, "geçerli dizini say" durumuna ls|lcbakarsanız, alabileceğiniz kadar özlüdür.


2

Şimdiye kadar Aaron's, kendi yaklaşımınızdan daha özlü tek yaklaşımdır. Yaklaşımınızın daha doğru bir sürümü şöyle görünebilir:

ls -aR1q | grep -Ecv '^\./|/$|^$'

Bu, yazdırılamayan karakterleri değiştirmek için kabuk kabuklarını kullanarak geçerli dizinin altındaki .dotfiles dahil olmak üzere tüm dosyaları (dizinleri değil) yinelemeli olarak listeler. grep, üst dizin listelerini veya .. veya * / veya boş satırları filtreler - bu nedenle dosya başına yalnızca bir satır olmalıdır - toplam grep sayısı size geri döner. Alt dizinlerin de eklenmesini istiyorsanız:

ls -aR1q | grep -Ecv '^\.{1,2}/|^$'

-RYinelemeli sonuçlar istemiyorsanız her iki durumda da çıkartın .


1
Böyle bir şey yapmayı tercih ediyorum find. Sadece bir sayım istiyorsanız, bunun çalışması gerekir: find -mindepth 1 -maxdepth 1 -printf '\n'|wc -l(özyinelemeli sonuçlar almak için derinlik kontrollerini kaldırın).
Aaron Davies

@AaronDavies - bu gerçekten işe yaramıyor. Bu dosya adlarının herhangi birine yeni bir satır ekleyin ve kendiniz görün. Ayrıca, aynı şeyi portatif olarak yapmak için: find . \! -name . -prune | wc -l- tabii ki hala çalışmıyor.
mikeserv

1
Takip etmiyorum - printftalimat, dosya adını hiç içermeyen sabit bir dize (yeni satır) yazdırır, bu nedenle sonuçlar herhangi bir garip dosya adından bağımsızdır. Elbette bu hile findhiç desteklenmeyen bir şeyle yapılamaz printf.
Aaron Davies

@AaronDavies - oh, doğru. Dosya adının eklendiğini varsaydım. Tabii ki find .//. \!. -name . -prune | grep -c '^\.//\.'
portatif

parlak! /dosya adlarında görünmeyen tek karakter olduğundan, .//.dizinin her dosya için tam olarak bir kez görünmesi garanti edilir, değil mi? birkaç soru - neden .//.ve neden -prune? bu ne zaman farklı olurdu find . \! -name . | grep -c '^\.'? (Ben .senin \!.bir yazım hatası olduğunu varsayalım .)
Aaron Davies
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.