Jak mogę uzyskać rozmiar pliku w skrypcie bash?
Jak przypisać to do zmiennej bash, aby móc jej później użyć?
pv
i cat
dla polecenia kopiowania, które pokazuje postęp i ETA :)
Jak mogę uzyskać rozmiar pliku w skrypcie bash?
Jak przypisać to do zmiennej bash, aby móc jej później użyć?
pv
i cat
dla polecenia kopiowania, które pokazuje postęp i ETA :)
Odpowiedzi:
Twój najlepszy zakład, jeśli w systemie GNU:
stat --printf="%s" file.any
Całkowity rozmiar% s, w bajtach
W skrypcie bash:
#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."
UWAGA: patrz odpowiedź @ chbrown, aby dowiedzieć się, jak używać statystyki w terminalu w systemie Mac OS X.
stat
jest najprostszym sposobem, zakładając, że używasz Linuksa lub Cygwina ( stat
nie jest standardem). wc -c
jak sugeruje Eugéne, jest przenośny.
stat: illegal option -- c
stat --printf="%s" file.txt
nie
stat -f%z myfile.tar
man stat
mówi, że --printf pomija końcowy znak nowej linii. Użyj --format
lub, -c
aby zobaczyć wynik. Zyskaj więcej wglądu w porównaniu stat --printf="%s" file.any | xxd -
dostat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
Problem z używaniem stat
polega na tym, że jest to rozszerzenie GNU (Linux). du -k
i cut -f1
są określone przez POSIX, a zatem są przenośne dla dowolnego systemu Unix.
Na przykład Solaris jest dostarczany z bash, ale nie z stat
. Nie jest to więc całkowicie hipotetyczne.
ls
ma podobny problem, ponieważ nie określono dokładnego formatu danych wyjściowych, dlatego parsowanie danych wyjściowych nie jest możliwe przenośne. du -h
jest także rozszerzeniem GNU.
Trzymaj się przenośnych konstrukcji tam, gdzie to możliwe, a ułatwisz komuś życie w przyszłości. Może twój własny.
du
nie podaje rozmiaru pliku, lecz wskazuje nieco ilość miejsca, które zajmuje plik, który jest nieznacznie inny (zwykle rozmiar zgłaszany przez du
to rozmiar pliku zaokrąglony w górę do najbliższej liczby bloków, gdzie blok jest zwykle 512B lub 1kB lub 4kB).
--bytes
lub -b
zamiast -k
, powinno być przyjętą odpowiedzią.
-h
(„ludzka”)du
daje najbardziej odpowiednią odpowiedź dla ogólnych przypadków: file_size=`du -h "$filename" | cut -f1
ponieważ wyświetli odpowiednio K (kilobajty), M (megabajty) lub G (gigabajty).
-h
jest rozszerzeniem GNU; to nie jest standardowe
Możesz także użyć polecenia „liczba słów” ( wc
):
wc -c "$filename" | awk '{print $1}'
Problem wc
polega na tym, że dodaje nazwę pliku i wcina dane wyjściowe. Na przykład:
$ wc -c somefile.txt
1160 somefile.txt
Jeśli chcesz uniknąć tworzenia łańcuchów tłumaczonych w pełnym języku lub edytora strumieniowego, aby uzyskać liczbę plików, po prostu przekieruj dane wejściowe z pliku, aby wc
nigdy nie widział nazwy pliku:
wc -c < "$filename"
Ta ostatnia forma może być używana z zastępowaniem poleceń, aby łatwo pobrać wartość, której szukałeś jako zmienną powłoki, jak wspomniano poniżej Gilles .
size="$(wc -c <"$filename")"
wc -c <"$FILENAME"
daje więc rozmiar bez żadnych innych cruft size=$(wc -c <"$FILENAME")
.
wc -c < file
wydaje się być bardzo szybki, przynajmniej na OS X. Zgaduję, że wc ma mózg, aby spróbować statycznie zapisać plik, jeśli podano tylko -c.
wc -c
używa fstat
, ale następnie szuka drugiego bloku pliku i odczytuje ostatnie st_blksize
bajty. Najwyraźniej dzieje się tak, ponieważ pliki w Linuksie /proc
i /sys
na przykład mają rozmiary statystyk, które są jedynie przybliżone , i wc
chcą zgłosić rzeczywisty rozmiar, a nie rozmiar podany w statystykach. Zgaduję, że wc -c
zgłaszanie innego rozmiaru byłoby dziwniejsze wc
, ale nie jest pomysłem odczytywanie danych z pliku, jeśli jest to zwykły plik na dysku i nie ma go w pamięci. Albo gorzej, przechowywanie na taśmie w pobliżu linii ...
printf
nadal widzi wcięcie, np. printf "Size: $size"
-> size: <4 spaces> 54339
. Z drugiej strony echo
ignoruje białe znaki. W jakikolwiek sposób, aby był spójny?
fstat
. Spróbuj uruchomić, strace wc -c </etc/passwd
a zobaczysz, co robi.
BSD (Mac OS X) stat
ma inną flagę argumentów formatu i różne specyfikatory pól. Od man stat(1)
:
-f format
: Wyświetlanie informacji przy użyciu określonego formatu. Zobacz poprawne formaty w sekcji FORMATY.z
: Rozmiar pliku w bajtach.Więc teraz wszyscy razem:
stat -f%z myfile1.txt
Zależy, co rozumiesz przez rozmiar .
size=$(wc -c < "$file")
poda liczbę bajtów, które można odczytać z pliku. IOW, jest to rozmiar zawartości pliku. Odczyta jednak zawartość pliku (z wyjątkiem sytuacji, gdy plik jest zwykłym plikiem lub dowiązaniem symbolicznym do zwykłego pliku w większości wc
implementacji jako optymalizacja). To może mieć skutki uboczne. Na przykład dla nazwanego potoku to, co zostało przeczytane, nie może być ponownie odczytane, a dla rzeczy takich jak /dev/zero
lub /dev/random
o nieskończonej wielkości zajmie to trochę czasu. Oznacza to również, że potrzebujesz read
uprawnień do pliku, a znacznik czasu ostatniego dostępu do pliku może zostać zaktualizowany.
Jest to standardowe i przenośne, jednak należy pamiętać, że niektóre wc
implementacje mogą zawierać wiodące spacje na tym wyjściu. Jednym ze sposobów na pozbycie się ich jest użycie:
size=$(($(wc -c < "$file")))
lub aby uniknąć błędu związanego z pustym wyrażeniem arytmetycznym w dash
lub yash
gdy wc
nie generuje danych wyjściowych (np. gdy nie można otworzyć pliku):
size=$(($(wc -c < "$file") +0))
ksh93
ma wc
wbudowaną funkcję (pod warunkiem, że ją włączysz, możesz ją również wywołać jako command /opt/ast/bin/wc
), co czyni ją najbardziej wydajną dla zwykłych plików w tej powłoce.
Różne systemy mają wywołane polecenie, stat
które jest interfejsem do wywołań systemowych stat()
lub lstat()
.
Raportują informacje znalezione w i-węźle. Jedną z tych informacji jest st_size
atrybut. W przypadku zwykłych plików jest to rozmiar zawartości (ile danych można odczytać z niej przy braku błędu (tego większość wc -c
implementacji używa do optymalizacji). W przypadku dowiązań symbolicznych jest to rozmiar w bajtach ścieżki docelowej. W przypadku nazwanych potoków, w zależności od systemu, jest to 0 lub liczba bajtów aktualnie w buforze potoków. To samo dotyczy urządzeń blokowych, gdzie w zależności od systemu otrzymujesz 0 lub rozmiar w bajtach pamięci podstawowej.
Nie potrzebujesz uprawnień do odczytu pliku, aby uzyskać te informacje, tylko uprawnienia do wyszukiwania w katalogu, do którego jest on podłączony.
W porządku chronologicznym istnieje:
IRIXstat
(lata 90-te):
stat -qLs -- "$file"
zwraca st_size
atrybut $file
( lstat()
) lub:
stat -s -- "$file"
to samo, z wyjątkiem sytuacji, gdy $file
jest dowiązaniem symbolicznym, w którym to przypadku jest to st_size
plik po rozdzieleniu dowiązania symbolicznego.
zsh
stat
wbudowany (obecnie znany również jako zstat
) w zsh/stat
module (załadowany zmodload zsh/stat
) (1997):
stat -L +size -- $file # st_size of file
stat +size -- $file # after symlink resolution
lub do przechowywania w zmiennej:
stat -L -A size +size -- $file
oczywiście jest to najbardziej wydajny w tej powłoce.
GNUstat
(2001); także w BusyBox stat
od 2005 roku (skopiowane z GNU stat
):
stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
(zauważ, że znaczenie -L
jest odwrócone w porównaniu do IRIX lub zsh
stat
.
BSDstat
(2002):
stat -f %z -- "$file" # st_size of file
stat -Lf %z -- "$file" # after symlink resolution
Lub możesz użyć funkcji stat()
/ lstat()
jakiegoś języka skryptowego, takiego jak perl
:
perl -le 'print((lstat shift)[7])' -- "$file"
System AIX zawiera również istat
polecenie, które zrzuci wszystkie informacje stat()
(nie lstat()
, więc nie będzie działać na dowiązaniach symbolicznych) i które można przetworzyć później , na przykład:
LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
(dzięki @JeffSchaller za pomoc w ustaleniu szczegółów ).
W tcsh
:
@ size = -Z $file:q
(rozmiar po rozdzielczości dowiązania symbolicznego)
Na długo przed wprowadzeniem stat
polecenia GNU to samo można osiągnąć dzięki find
poleceniu GNU z jego -printf
predykatem (już w 1991 r.):
find -- "$file" -prune -printf '%s\n' # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution
Jednym z problemów jest jednak, że nie działa, jeśli $file
rozpoczyna się -
lub jest find
orzeczenie (jak !
, (
...).
Standardowe polecenie, aby uzyskać informacje stat()
/, lstat()
to ls
.
POSIXly możesz:
LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
i dodaj -L
to samo po rozwiązaniu dowiązania symbolicznego. To nie działa w przypadku plików urządzeń, gdzie 5- tym polem jest numer główny urządzenia zamiast jego rozmiaru.
W przypadku urządzeń blokowych systemy, w których stat()
zwraca 0 st_size
, zwykle mają inne interfejsy API do zgłaszania wielkości urządzenia blokowego. Na przykład Linux ma BLKGETSIZE64
ioctl()
i większość dystrybucji Linuksa jest teraz dostarczana z blockdev
poleceniem, które może z niego skorzystać:
blockdev --getsize64 -- "$device_file"
W tym celu potrzebujesz jednak uprawnienia do odczytu pliku urządzenia. Zwykle można uzyskać rozmiar w inny sposób. Na przykład (wciąż w systemie Linux):
lsblk -bdno size -- "$device_file"
Powinien działać, z wyjątkiem pustych urządzeń.
Podejście, które działa dla wszystkich widocznych plików (a więc obejmuje zwykłe pliki, większość urządzeń blokowych i niektóre urządzenia znakowe), polega na otwarciu pliku i szukaniu do końca:
Z zsh
(po załadowaniu zsh/system
modułu):
{sysseek -w end 0 && size=$((systell(0)))} < $file
Z ksh93
:
< "$file" <#((size=EOF))
lub
{ size=$(<#((EOF))); } < "$file"
z perl
:
perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"
Dla nazwanych potoków, widzieliśmy, że niektóre systemy (AIX, Solaris, HP / UX przynajmniej) sprawiają, że ilość danych w buforze rur dostępnych w stat()
„s st_size
. Niektóre (jak Linux lub FreeBSD) nie.
Przynajmniej w systemie Linux możesz użyć następującego FIONREAD
ioctl()
po otwarciu potoku (w trybie odczytu + zapisu, aby go nie zawiesić):
fuser -s -- "$fifo_file" &&
perl -le 'require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die$!;
print unpack "L", $n' <> "$fifo_file"
Należy jednak pamiętać, że chociaż nie odczytuje zawartości potoku, samo otwarcie nazwanej potoku tutaj może nadal mieć skutki uboczne. Używamy fuser
najpierw do sprawdzenia, czy jakiś proces ma już otwartą rurkę, aby to złagodzić, ale nie jest to niezawodne, ponieważ fuser
może nie być w stanie sprawdzić wszystkich procesów.
Do tej pory rozważaliśmy jedynie rozmiar podstawowych danych powiązanych z plikami. To nie bierze pod uwagę rozmiaru metadanych i całej infrastruktury pomocniczej potrzebnej do przechowywania tego pliku.
Kolejnym atrybutem i-węzła zwróconym przez stat()
jest st_blocks
. Jest to liczba 512-bajtowych bloków używanych do przechowywania danych pliku (a czasem niektórych jego metadanych, takich jak rozszerzone atrybuty w systemach plików ext4 w systemie Linux). Nie obejmuje to samego i-węzła ani wpisów w katalogach, z którymi plik jest powiązany.
Rozmiar i użycie dysku niekoniecznie są ściśle związane z kompresją, rzadkością (czasami niektóre metadane), dodatkowa infrastruktura, taka jak bloki pośrednie w niektórych systemach plików, ma na to wpływ.
Tego zwykle du
używa się do zgłaszania użycia dysku. Większość wyżej wymienionych poleceń będzie w stanie uzyskać te informacje.
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
POSIXLY_CORRECT=1 du -s -- "$file"
(nie dotyczy katalogów, w których obejmowałoby to użycie plików na dysku).find -- "$file" -printf '%b\n'
zstat -L +block -- $file
stat -c %b -- "$file"
stat -f %b -- "$file"
perl -le 'print((lstat shift)[12])' -- "$file"
wc -c
używa fstat
, ale potem odczytuje ostatnie st_blksize
bajty. Najwyraźniej dzieje się tak, ponieważ pliki w Linuksie /proc
i /sys
na przykład mają rozmiary statystyk, które są jedynie przybliżone . Jest to dobre dla poprawności, ale złe, jeśli koniec pliku znajduje się na dysku, a nie w pamięci (szczególnie jeśli jest używany na wielu plikach w pętli). I bardzo źle, jeśli plik jest migrowany do pamięci taśmowej nearline lub np. Systemu plików FUSE z przezroczystą dekompresją.
ls -go file | awk '{print $3}'
-go
byłyby to SysV, nie działałyby na BSD (opcjonalnie (XSI) w POSIX). Potrzebujesz również ls -god file | awk '{print $3; exit}'
( -d
aby działał na katalogach, exit
dla dowiązań symbolicznych z nowymi liniami w celu). Pozostają również problemy z plikami urządzeń.
wc -c
która podaje liczbę bajtów.
Ten skrypt łączy wiele sposobów obliczania rozmiaru pliku:
(
du --apparent-size --block-size=1 "$file" 2>/dev/null ||
gdu --apparent-size --block-size=1 "$file" 2>/dev/null ||
find "$file" -printf "%s" 2>/dev/null ||
gfind "$file" -printf "%s" 2>/dev/null ||
stat --printf="%s" "$file" 2>/dev/null ||
stat -f%z "$file" 2>/dev/null ||
wc -c <"$file" 2>/dev/null
) | awk '{print $1}'
Skrypt działa na wielu systemach uniksowych, w tym Linux, BSD, OSX, Solaris, SunOS itp.
Rozmiar pliku pokazuje liczbę bajtów. Jest to rozmiar pozorny, który jest bajtami używanymi przez plik na typowym dysku, bez specjalnej kompresji, specjalnych rzadkich obszarów lub nieprzydzielonych bloków itp.
Ten skrypt ma wersję produkcyjną z dodatkową pomocą i więcej opcji tutaj: https://github.com/SixArm/file-size
stat wydaje się to robić przy najmniejszej liczbie wywołań systemowych:
$ set debian-live-8.2.0-amd64-xfce-desktop.iso
$ strace stat --format %s $1 | wc
282 2795 27364
$ strace wc --bytes $1 | wc
307 3063 29091
$ strace du --bytes $1 | wc
437 4376 41955
$ strace find $1 -printf %s | wc
604 6061 64793
ls -l filename
poda wiele informacji o pliku, w tym jego rozmiar, uprawnienia i właściciela.
Rozmiar pliku w piątej kolumnie i jest wyświetlany w bajtach. W poniższym przykładzie rozmiar pliku wynosi nieco poniżej 2 KB:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Edycja: najwyraźniej nie jest tak niezawodny jak stat
polecenie.
ls -l
i stat
polecenie podają wiarygodne informacje o rozmiarze. Nie znalazłem żadnego odniesienia do czegoś przeciwnego. ls -s
da rozmiar w liczbie bloków.
du filename
poinformuje cię o zużyciu dysku w bajtach.
Wolę du -h filename
, co daje rozmiar w formacie czytelnym dla człowieka.
du
wydruku wielkości w blokach 1024 bajtów, a nie zwykła liczba bajtów.
du
daje wyjście w liczbie 512-bajtowych jednostek. GNU du
używa zamiast tego kibibajtów, chyba że jest wywoływane POSIXLY_CORRECT
w jego środowisku.
Twórz małe funkcje narzędziowe w swoich skryptach powłoki, które możesz delegować.
Przykład
#! /bin/sh -
# vim: set ft=sh
# size utility that works on GNU and BSD systems
size(){
case $(uname) in
(Darwin | *BSD*)
stat -Lf %z -- "$1";;
(*) stat -c %s -- "$1"
esac
}
for f do
printf '%s\n' "$f : $(gzip < "$f" | wc -c) bytes (versus $(size "$f") bytes)"
done
Na podstawie informacji uzyskanych z odpowiedzi @ Stéphane Chazelas.
gzip -v < file > /dev/null
aby sprawdzić kompresję pliku.
case
oświadczenia. case
jest konstrukcją Bourne / POSIX, która wykonuje dopasowanie wzorca. [[...]]
jest tylko ksh / bash / zsh (z odmianami).
Znalazłem wkładkę AWK 1 i miał błąd, ale go naprawiłem. Dodałem także w PetaBytes po TeraBytes.
FILE_SIZE=234234 # FILESIZE IN BYTES
FILE_SIZE=$(echo "${FILE_SIZE}" | awk '{ split( "B KB MB GB TB PB" , v ); s=1; while( $1>1024 ){ $1/=1024; s++ } printf "%.2f %s", $1, v[s] }')
Biorąc pod uwagę, że statystyki nie są dostępne w każdym systemie, prawie zawsze można użyć rozwiązania AWK. Przykład; Raspberry Pi nie ma statystyk, ale ma awk .
Jeden inny sposób zgodny z POSIX byłoby użyć awk
z jego length()
funkcji, która zwraca długość, w znakach na każdej linii pliku wejściowego, z wyjątkiem nowej linii znaków. Tak robiąc
awk '{ sum+=length } END { print sum+NR }' file
zapewniamy, że NR
jest dodawany do sum
, dzięki czemu łączna liczba znaków i całkowita liczba nowych linii napotkanych w pliku. length()
Funkcja w awk
przyjmuje argument, który domyślnie środek length($0)
, który jest dla bieżącego całej linii.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
powinien wypisać 3, ale wypisuje 4.
Sam lubię opcję wc. W połączeniu z „bc” możesz uzyskiwać liczby dziesiętne w dowolnej liczbie miejsc.
Szukałem ulepszenia skryptu, który wybudził kolumnę „rozmiar pliku” polecenia „ls -alh”. Nie chciałem tylko liczb całkowitych, a dwa miejsca po przecinku wydawały się pasować, więc po przeczytaniu tej dyskusji wymyśliłem poniższy kod.
Sugeruję przerwanie linii w średnikach, jeśli umieścisz to w skrypcie.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Mój skrypt nazywa się gpfl , ponieważ „pobierz długość pliku obrazu”. Używam go po zrobieniu zdjęcia pliku w imagemagick, przed otwarciem lub ponownym załadowaniem obrazu w przeglądarce jpeg z GUI.
Nie wiem, jak to ocenia się jako „odpowiedź”, ponieważ wiele zapożycza z tego, co zostało już zaoferowane i omówione. Więc zostawię to tam.
BZT
wc
czyta ostatni blok pliku, na wypadek gdyby stat.st_size
było to tylko przybliżenie (jak w przypadku Linuksa /proc
i /sys
plików). Myślę, że nie zdecydował się na głównym komentarz bardziej skomplikowana, gdy dodał, że logika paru linie w dół: lingrok.org/xref/coreutils/src/wc.c#246
Najszybsza i najprostsza metoda (IMO) to:
bash_var=$(stat -c %s /path/to/filename)
du
i wc
odpowiedzi, które powinny zawierać zastrzeżenie, NIGDY NIE RÓŻ TEGO W ŻYCIU. Właśnie użyłem swojej odpowiedzi w dzisiejszej aplikacji z życia i pomyślałem, że warto się nią podzielić. Chyba wszyscy mamy swoje opinie wzruszają ramionami .