Kabukta dosya boyutunu (bayt cinsinden) almanın taşınabilir yolu?


121

Linux'ta kullanıyorum stat --format="%s" FILE, ancak Solaris'e erişimim var stat komutuna sahip değil. O halde ne kullanmalıyım?

Bash betikleri yazıyorum ve sisteme gerçekten yeni bir yazılım yükleyemiyorum.

Zaten kullanmayı düşündüm:

perl -e '@x=stat(shift);print $x[7]' FILE

ya da:

ls -nl FILE | awk '{print $5}'

Ama bunların hiçbiri mantıklı görünmüyor - Perl'i sadece dosya boyutunu elde etmek için çalıştırmak mı? Veya aynısını yapmak için 2 komut mu çalıştırıyorsunuz?


1
bir bash betiği bir yazılımdır ve bunu sisteme koyabilirseniz, yazılımı yükleyebilirsiniz.
sadece birisi

4
Teknik olarak - doğru. Kök ayrıcalıklarına sahip olmadığımı ve yeni paketler kuramadığımı kastettim. Elbette ana dizine yüklemek mümkündür. Ama betiği taşınabilir yapmam ve "X" makinelerine yüklemem gerektiğinde, yeni ek paketler zorlaşır.

Yanıtlar:


207

wc -c < filename(kelime sayımının kısaltması -c, bayt sayısını yazdırır) taşınabilir bir POSIX çözümüdür. Bazı boşlukların başına eklenebileceğinden (Solaris için durum böyledir) yalnızca çıktı formatı platformlar arasında tek tip olmayabilir.

Giriş yönlendirmesini ihmal etmeyin. Dosya bir bağımsız değişken olarak aktarıldığında, dosya adı bayt sayımından sonra yazdırılır.

İkili dosyalar için çalışmayacağından endişeliydim, ancak hem Linux hem de Solaris'te sorunsuz çalışıyor. İle deneyebilirsiniz wc -c < /usr/bin/wc. Ayrıca, aksi açıkça belirtilmedikçe , POSIX yardımcı programlarının ikili dosyaları işlemesi garanti edilir .


67
Veya sadece wc -c < filedosya adının görünmesini istemiyorsanız.
caf

34
Yine de yanılmıyorsam, wcbir ardışık read()düzen içinde baytları saymak için tüm akışın olması gerekir . ls/ awkÇözeltileri (ve benzeri) boyutu elde etmek için bir sistem çağrısı kullanmak gerekir (O (boyut) karşı), doğrusal bir zaman
jmtd

1
Bunu wcen son tam sabit diskte yaptığımda çok yavaş olduğumu hatırlıyorum . İlk bitmeden senaryoyu yeniden yazabileceğim kadar yavaştı, buraya nasıl yaptığımı hatırlamaya geldim lol.
Camilo Martin

6
Ben kullanmazdım wc -c; çok daha düzgün görünüyor ancak ls+ awkhız / kaynak kullanımı için daha iyi. Ayrıca, sonuçlarını gerçekten de sonradan işlemeye ihtiyacınız olduğunu belirtmek isterim wcçünkü bazı sistemlerde sonuçtan önce boşluklar olacaktır, bu da karşılaştırma yapmadan önce çıkarmanız gerekebilir.
Haravikk

3
wc -charika, ancak dosyaya okuma erişiminiz yoksa işe yaramayacak.
Silas

41

Sadece boyutunu görüntülemek için kendi programımı (gerçekten küçük) yazdım. Daha fazla bilgi burada: http://fwhacking.blogspot.com/2011/03/bfsize-print-file-size-in-bytes-and.html

Bence yaygın Linux araçlarıyla ilgili en temiz iki yol:

$ stat -c %s /usr/bin/stat
50000

$ wc -c < /usr/bin/wc
36912

Ama sadece bir dosya boyutu elde etmek için parametreler yazmak veya çıktıyı yönlendirmek istemiyorum, bu yüzden kendi bfsize'mi kullanıyorum.


2
Problem tanımının ilk satırı, stat'ın bir seçenek olmadığını ve wc -c'nin bir yıldan fazla bir süredir en iyi cevap olduğunu belirtiyor, bu yüzden bu cevabın amacı ne olduğundan emin değilim.

22
Nokta Google bu SO soru bulmak ve benim gibi insanlar olduğunu stat olduğunu onlar için bir seçenek.
yo '

3
wc -c10 MB'lık bir dosyada 4090 milisaniye ve "0" milisaniye süren gömülü bir sistem üzerinde çalışıyorum stat -c %s, bu yüzden sorulan soruya tam olarak cevap vermeseler bile alternatif çözümlere sahip olmanın yararlı olduğunu kabul ediyorum.
Robert Calhoun

3
"stat -c" taşınabilir değildir / Linux'ta olduğu gibi MacOS'ta da aynı argümanları kabul etmez. "wc -c", büyük dosyalar için çok yavaş olacaktır.
Orwellophile

2
stat taşınabilir de değildir. stat -c %s /usr/bin/stat stat: illegal option -- c usage: stat [-FlLnqrsx] [-f format] [-t timefmt] [file ...]

27

Olsa dugenellikle disk kullanımını değil, gerçek veri boyutunu yazdırır, GNU coreutils dudosyanın "görünen boyutu" bayt yazdırabilirsiniz:

du -b FILE

Ancak BSD, Solaris, macOS, ... altında çalışmaz.


3
MacOS X'te brew install coreutilsve gdu -baynı etkiyi elde edecek
Jose Alban

1
Bu yöntemi tercih ediyorum çünkü wcbir sonuç vermeden önce dosyanın tamamını okumak gerekiyor du, hemen oluyor.
CousinCocaine

2
POSIX mantıksal olarakdu -b tamamen farklı bir bağlamda bahseder . du
Palec

Bu sadece lstataramayı kullanır , dolayısıyla performansı dosya boyutuna bağlı değildir. Daha kısa stat -c '%s', ancak daha az sezgiseldir ve klasörler için farklı çalışır (içindeki her dosyanın boyutunu yazdırır).
Palec

FreeBSDdu kullanarak yaklaşabilir du -A -B1, ancak yine de sonucu 1024B bloğun katları halinde yazdırır. Bayt sayısını yazdırmayı başaramadı. BLOCKSIZE=1Ortamda ayar yapmak bile yardımcı olmuyor, çünkü o zaman 512B bloğu kullanılıyor.
Palec

13

Sonunda ls ve bash dizi genişletmesini kullanmaya karar verdim:

TEMP=( $( ls -ln FILE ) )
SIZE=${TEMP[4]}

gerçekten hoş değil, ama en azından sadece 1 fork + execve yapar ve ikincil programlama diline (perl / ruby ​​/ python / her neyse) dayanmaz


Sadece bir kenara - '-ln' içindeki 'l' gerekli değildir; '-n', '-ln' ile tamamen aynıdır
barryred

Hayır değil. Sadece çıktıları karşılaştırın.

1
Taşınabilir ls -ln FILE | { read _ _ _ _ size _ && echo "$size"; }ihtiyaçların ardışık düzeninin ikinci adımı için çatallanmayacağını tahmin edebilir , çünkü yalnızca yerleşikleri kullanır, ancak Linux çatallarında iki kez Bash 4.2.37 (yine de yalnızca bir tane execve).
Palec

read _ _ _ _ size _ <<<"$(exec ls -ln /usr/bin/wc)" && echo "$size"tek çatal ve tek yürütme ile çalışır, ancak buradaki dizge için geçici bir dosya kullanır. Buradaki dizeyi POSX uyumlu buradaki belge ile değiştirerek taşınabilir hale getirilebilir . BTW execalt kabuğa dikkat edin . Bu olmadan, Bash alt kabuk için bir çatal ve içeride çalışan komut için başka bir çatal gerçekleştirir. Bu cevapta verdiğiniz kodda durum budur. çok.
Palec

1
-lVarlığında, gereksiz -n. Aktaran POSIX lsmanpage : -naçın: -l(ell) seçeneği, ancak dosyanın sahibini veya grubu yazarken sırasıyla kullanıcı veya grup adı yerine dosyanın sayısal UID veya GID yazın. Devre dışı -C, -mve -xseçenekleri.
Palec

8

Çapraz platform en hızlı çözüm ( ls için yalnızca tek çatal () kullanır , gerçek karakterleri saymaya çalışmaz, gereksiz awk, perl vb. Üretmez).

MacOS, Linux üzerinde test edilmiştir - Solaris için küçük değişiklikler gerektirebilir:

__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"

Gerekirse, ls bağımsız değişkenlerini basitleştirin ve $ {__ ln [3]} 'de göreli konumu ayarlayın.

Not: sembolik bağlantıları izleyecektir.


1
Veya bir kabuk betiğine koyun: ls -Lon "$ 1" | awk '{print $ 4}'
Luciano

1
Tamamen sizi noktası cevapsız düşünüyorum @Luciano çatallama değil ve bir görevi yapıyor bash yerine unix bir çok verimsiz bir şekilde bir araya komutları dizeye bash kullanarak daha.
Orwellophile


6

ls -nÇıktıyı işlerken , taşınabilir olmayan kabuk dizilerine alternatif olarak, tek diziyi oluşturan ve standart kabuktaki tek yerel değişkenler olan konumsal bağımsız değişkenleri kullanabilirsiniz. Komut dosyanız veya işleviniz için orijinal bağımsız değişkenleri korumak için bir işlevde konumsal bağımsız değişkenlerin üzerine yazılmasını sarın.

getsize() { set -- $(ls -dn "$1") && echo $5; }
getsize FILE

Bu, çıkışını ln -dnmevcut IFSortam değişkeni ayarlarına göre böler, onu konumsal argümanlara atar ve beşinciyi yansıtır. -dOlmasını sağlar dizinleri düzgün işlenir ve -nkullanıcı ve grup adları gerekmez güvence veriyor farklı olarak, çözülecek -l. Ayrıca, boşluk içeren kullanıcı ve grup adları teorik olarak beklenen satır yapısını bozabilir; genellikle izin verilmez, ancak bu olasılık yine de programcının durup düşünmesine neden olur.


5

Eğer kullanırsanız findGNU fileutils gelen:

size=$( find . -maxdepth 1 -type f -name filename -printf '%s' )

Ne yazık ki, diğer uygulamalar findgenellikle desteklemiyor -maxdepth, ne de -printf. Örneğin Solaris ve macOS için durum budur find.


Bilginize maxdepth gerekli değildir. Olarak yeniden yazılabilir size=$(test -f filename && find filename -printf '%s').
Palec

@Palec:, özyinelemeli olmayı -maxdepthönlemek için tasarlanmıştır find(çünkü statOP'nin değiştirilmesi gereken şey değildir). Sizin findkomutu bir eksik -nameve testkomut gerekli değildir.
sonraki duyuruya kadar duraklatıldı.

@DennisWilliamson find, parametrelerini verilen kriterlere uyan dosyalar için yinelemeli olarak arar. Parametreler dizin değilse, özyineleme ... oldukça basittir. Bu nedenle önce filenamegerçekten var olan sıradan bir dosyayı test ediyorum ve sonra boyutunu findtekrarlayacak yeri olmayan bir dosya kullanarak yazdırıyorum .
Palec

1
find . -maxdepth 1 -type f -name filename -printf '%s'yalnızca dosya geçerli dizindeyse çalışır ve dizindeki her dosyayı incelemeye devam edebilir, bu da yavaş olabilir. Daha iyi kullanım (daha da kısa!) find filename -maxdepth 1 -type f -printf '%s'.
Palec

3

findBazı dosya kümelerini almak için command kullanabilirsiniz (burada geçici dosyalar çıkarılır). Ardından, switch'i dukullanarak her dosyanın dosya boyutunu insan tarafından okunabilir biçimde almak için komutu kullanabilirsiniz -h.

find $HOME -type f -name "*~" -exec du -h {} \;

ÇIKTI:

4.0K    /home/turing/Desktop/JavaExmp/TwoButtons.java~
4.0K    /home/turing/Desktop/JavaExmp/MyDrawPanel.java~
4.0K    /home/turing/Desktop/JavaExmp/Instream.java~
4.0K    /home/turing/Desktop/JavaExmp/RandomDemo.java~
4.0K    /home/turing/Desktop/JavaExmp/Buff.java~
4.0K    /home/turing/Desktop/JavaExmp/SimpleGui2.java~

2

İlk Perl örneğiniz bana mantıksız görünmüyor.

Bunun gibi nedenlerden dolayı kabuk betikleri yazmaktan (bash / sh vb.) Perl'de en önemsiz betikleri yazmaya geçtim. Belirli gereksinimler için Perl'i başlatmak zorunda olduğumu fark ettim ve bunu gittikçe daha fazla yaptıkça, Perl'de betik yazmanın muhtemelen daha güçlü olduğunu fark ettim (dil ve CPAN aracılığıyla kullanılabilen geniş kütüphane yelpazesi açısından) ) ve istediğimi elde etmenin daha verimli bir yolu.

Diğer kabuk-betikleme dillerinin (ör. Python / ruby) şüphesiz benzer olanaklara sahip olacağını ve bunları kendi amaçlarınız için değerlendirmek isteyebileceğinizi unutmayın. Sadece Perl'den bahsediyorum çünkü kullandığım ve aşina olduğum dil bu.


Eh, kendim için çok fazla Perl yazıyorum, ancak bazen araç benim için değil, benim için

-3

Solaris'inizde Perl varsa, onu kullanın. Aksi takdirde, bir sonraki en iyi seçeneğiniz ls with awk olacaktır, çünkü statünüz yoktur veya bulduğunuz GNU find değildir.


-3

Solaris'te kullandığım bir numara var, eğer birden fazla dosyanın boyutunu sorarsanız, sadece isimsiz toplam boyutu döndürür - bu nedenle ikinci dosya olarak / dev / null gibi boş bir dosya ekleyin:

eg komutu fileyouant / dev / null

Bunun ls / wc / etc için hangi boyut komutunun çalıştığını hatırlayamıyorum - ne yazık ki onu test etmek için bir solaris kutum yok.


-4

linux üzerinde kullanabilirsiniz du -h $FILE, bu solaris üzerinde de çalışıyor mu?


1
Aslında birimler dönüştürülebilir, ancak bu dosya veri boyutu ("görünen boyut") yerine disk kullanımını gösterir.
Palec

-7

Du -ks denediniz mi | awk '{baskı $ 1 * 1024}'. Bu sadece işe yarayabilir.


1
Bu, dosya veri boyutu ("görünen boyut") yerine disk kullanımını gösterir.
Palec
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.