Jak sprawdzić rozmiar pliku za pomocą Bash?

145

Mam skrypt, który sprawdza rozmiar 0, ale pomyślałem, że zamiast tego musi istnieć łatwiejszy sposób sprawdzania rozmiarów plików. To file.txtznaczy normalnie 100k; jak sprawić, by skrypt sprawdził, czy jest mniejszy niż 90k (w tym 0), i sprawić, by wykonał nową kopię, ponieważ w tym przypadku plik jest uszkodzony.

Czego obecnie używam…

if [ -n file.txt ]
then
 echo "everything is good"
else
 mail -s "file.txt size is zero, please fix. " myemail@gmail.com < /dev/null
 # Grab wget as a fallback 
 wget -c https://www.server.org/file.txt -P /root/tmp --output-document=/root/tmp/file.txt
 mv -f /root/tmp/file.txt /var/www/file.txt
fi
user349418
źródło
1
unix.stackexchange.com/questions/16640/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

250

[ -n file.txt ]nie sprawdza swojego rozmiaru, sprawdza, czy łańcuch file.txtma niezerową długość, więc zawsze się powiedzie.

Jeśli chcesz powiedzieć „rozmiar jest niezerowy”, potrzebujesz [ -s file.txt ].

Aby uzyskać rozmiar pliku, możesz użyć, wc -caby uzyskać rozmiar (długość pliku) w bajtach:

file=file.txt
minimumsize=90000
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi

W tym przypadku wygląda na to, że tego chcesz.

Ale do Twojej wiadomości, jeśli chcesz wiedzieć, ile miejsca na dysku zajmuje plik, możesz użyć du -kdo uzyskania rozmiaru (zajętego miejsca na dysku) w kilobajtach:

file=file.txt
minimumsize=90
actualsize=$(du -k "$file" | cut -f 1)
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize kilobytes
else
    echo size is under $minimumsize kilobytes
fi

Jeśli potrzebujesz większej kontroli nad formatem wyjściowym, możesz również spojrzeć na stat. W Linuksie zacząłbyś od czegoś takiego stat -c '%s' file.txt, a na BSD / Mac OS X, coś w stylu stat -f '%z' file.txt.

Mikel
źródło
5
Dlaczego du -b "$file" | cut -f 1zamiast stat -c '%s' "$file"? Albo stat --printf="%s" "$file"?
mivk
1
Tylko dlatego, że jest bardziej przenośny. BSD i Linux stat mają różne flagi.
Mikel
1
Musiałem go zmodyfikować ... | cut -d' ' -f1, aby działał na Ubuntu.
Mikepote
8
Użyj wc -c < "$file"(zwróć uwagę na <), w takim przypadku nie potrzebujesz | cut ...części (która, jak napisano, nie działa na OSX). Minimalna BLOCKSIZEwartość dla duw systemie OSX to 512.
mklement0
3
@PetriSirkkala W moim systemie Linux wc -c <filenameużywa również fstati seek? Zauważ, że fstatpobiera fd, a nie ścieżkę.
Mikel
24

Zaskakuje mnie, że nikt nie wspomniał stato sprawdzaniu rozmiaru pliku. Niektóre metody są zdecydowanie lepsze: użycie -sdo sprawdzenia, czy plik jest pusty, czy nie, jest łatwiejsze niż czegokolwiek innego, jeśli to wszystko, czego chcesz. A jeśli chcesz znaleźć pliki o dużym rozmiarze, z findpewnością jest to droga.

Bardzo lubię duteż uzyskiwać rozmiar pliku w kb, ale dla bajtów użyłbym stat:

size=$(stat -f%z $filename) # BSD stat

size=$(stat -c%s $filename) # GNU stat?
Daniel C. Sobral
źródło
2
statto świetny pomysł, ale na CentOS to właśnie zadziałało dla mnie:size=$(stat -c%s $filename)
Oz Solomon
2
Różnica między GNU a BSD niestety sprawia, że ​​ta alternatywa jest nieco mniej atrakcyjna. :(
lapo
1
stat może wprowadzać w błąd, jeśli plik jest rzadki. Możesz użyć bloków raportowanych przez statystyki, aby obliczyć wykorzystane miejsce.
Ajith Antony
@AjithAntony To interesujący punkt, który nie przyszedł mi do głowy. Widzę, statbędąc tuż rzeczą w niektórych sytuacjach i rzadkie pliki nie są odpowiednie w większości sytuacji, choć na pewno nie wszystkie.
Daniel C. Sobral
17

alternatywne rozwiązanie z awk i podwójnym nawiasem:

FILENAME=file.txt
SIZE=$(du -sb $FILENAME | awk '{ print $1 }')

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi
fstab
źródło
1
Fajnie, ale nie będzie działać na OSX, gdzie dunie obsługuje -b. (Może to być świadomy wybór stylu, ale po prostu wspomnieć alternatywę: można pominąć $wnętrze prefiksu (( ... ))przy odwoływaniu zmienne: ((SIZE<90000)))
mklement0
1
Właściwie była to edycja dokonana przez poprzedniego użytkownika, który uważał, że pomijanie$
fstab
2
@fstab, możesz ominąć awk, używając read( bashpolecenia wewnętrznego):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian
13

Jeśli Twoja findskładnia obsługuje tę składnię, możesz jej użyć:

find -maxdepth 1 -name "file.txt" -size -90k

Spowoduje to wyjście file.txtna stdout wtedy i tylko wtedy, gdy rozmiar file.txtjest mniejszy niż 90k. Aby wykonać skrypt, scriptjeśli file.txtma rozmiar mniejszy niż 90 KB:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
źródło
3
+1, ale aby działał również na OSX, potrzebujesz jawnego argumentu katalogu docelowego, np .:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0
8

Jeśli szukasz tylko rozmiaru pliku:

$ cat $file | wc -c
> 203233
BananaNeil
źródło
1
Może to być najkrótsza możliwa do zastosowania odpowiedź, ale prawdopodobnie jest też najwolniejsza. :)
SunSparc,
2
Tak, ale z pewnością ekonomicznie lepszy: Koszt czasu inżynierskiego> Koszt czasu obliczeń
BananaNeil
8
wc -c "$file"jako odpowiedź udzielono w 2011 r. (trzy lata temu). Tak, wc -c "$file"ma problem polegający na tym, że wyświetla nazwę pliku, a także liczbę znaków, więc wczesne odpowiedzi dodały polecenie oddzielenia liczby. Ale to wc -c < "$file", co rozwiązuje ten problem, zostało dodane jako komentarz w maju 2014 roku. Twoja odpowiedź jest równoważna z tym, że dodaje „bezużyteczne użycie cat . Powinieneś także cytować wszystkie odwołania do zmiennych powłoki, chyba że masz ku temu dobry powód.
G-Man mówi „Przywróć Monikę”
1
Możesz uczynić to bardziej wydajnym, używając head -c zamiast cat.if [$ (head -c 90000 $ plik | wc -c) -lt 90000]; następnie echo "Plik jest mniejszy niż 90 KB"; fi. Testowany na CentOS, więc może, ale nie musi działać na BSD lub OSX.
Kevin Keane
@BananaNeil jak wykonać ten proces co 20 sekund, abym mógł sprawdzić przyrost rozmiaru pliku?
Sahra
6

Działa to zarówno w systemie Linux, jak i macOS

function filesize
{
    local file=$1
    size=`stat -c%s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]
    then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]
    then
        echo $st_size
        return 0
    fi

    return -1
}
Neil McGill
źródło
5

stat wydaje się robić to z najmniejszą liczbą 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

źródło
Jeśli dobrze rozumiem, test powinien być wykonany również z przekierowaniem potoku ?: strace du --bytes $1 2>&1 >/dev/null | wc Jeśli tak jest, to na architekturze amd64 na ArchLinux (zwykle najnowsze wersje wszystkiego) mam 45 linii dla du, 46 linii dla stat, 47 linii dla wci 72 linie dla find.
VasiliNovikov
5
python -c 'import os; print (os.path.getsize("... filename ..."))'

przenośny, wszystkie odmiany Pythona, unika różnic w dialektach statystycznych

user6336835
źródło
4

Aby uzyskać rozmiar pliku zarówno w systemie Linux, jak i Mac OS X (i prawdopodobnie w innych BSD), nie ma wielu opcji, a większość z sugerowanych tutaj będzie działać tylko na jednym systemie.

Biorąc pod uwagę f=/path/to/your/file,

co działa w systemie Linux i Mac Bash:

size=$( perl -e 'print -s shift' "$f" )

lub

size=$( wc -c "$f" | awk '{print $1}' )

Pozostałe odpowiedzi działają dobrze w Linuksie, ale nie na Macu:

  • dunie ma -bopcji na Macu, a sztuczka BLOCKSIZE = 1 nie działa („minimalny rozmiar bloku to 512”, co prowadzi do nieprawidłowego wyniku)

  • cut -d' ' -f1 nie działa, ponieważ na Macu liczba może być wyrównana do prawej i uzupełniona spacjami z przodu.

Więc jeśli trzeba coś elastycznego, to albo perljest -soperator, lub wc -crurami do awk '{print $1}'(awk ignoruje wiodącą spacje).

Oczywiście, jeśli chodzi o resztę pierwotnego pytania, użyj operatora -lt(lub -gt):

if [ $size -lt $your_wanted_size ]; then itp.

mivk
źródło
3
+1; jeśli wiesz, że będziesz używać rozmiaru tylko w kontekście arytmetycznym (gdzie początkowe białe znaki są ignorowane), możesz uprościć do size=$(wc -c < "$f")(zwróć uwagę na <, co powoduje wczgłoszenie tylko liczby). Dla porównania: nie zapomnij o bardziej „bash-ful” if (( size < your_wanted_size )); then ...(a także [[ $size -lt $your_wanted_size ]]).
mklement0
3

Na podstawie odpowiedzi gniourf_gniourf,

find "file.txt" -size -90k

zapisze file.txtna stdout wtedy i tylko wtedy, gdy rozmiar file.txtjest mniejszy niż 90K, a

znajdź "plik.txt" -rozmiar -90k -exec polecenie \;

wykona polecenie, commandjeśli file.txtma rozmiar mniejszy niż 90 KB. Przetestowałem to w systemie Linux. Od find(1),

... Argumenty wiersza polecenia następujący ( -H, -Li -Popcje) są brane nazwy plików lub katalogów, które mają zostać zbadane, aż do pierwszego argumentu, który zaczyna się od „-”, ...

(podkreślenie dodane).

G-Man mówi „Przywróć Monikę”
źródło
1
ls -l $file | awk '{print $6}'

zakładając, że polecenie ls zgłasza rozmiar pliku w kolumnie # 6

yeugeniuss
źródło
1

Użyłbym du„s --thresholddo tego. Nie jestem pewien, czy ta opcja jest dostępna we wszystkich wersjach programu, duale została zaimplementowana w wersji GNU.

Cytując z podręcznika du (1) :

-t, --threshold=SIZE
       exclude entries smaller than SIZE if positive, or entries greater
       than SIZE if negative

Oto moje rozwiązanie, używając du --threshold=dla przypadku użycia OP:

THRESHOLD=90k
if [[ -z "$(du --threshold=${THRESHOLD} file.txt)" ]]; then
    mail -s "file.txt size is below ${THRESHOLD}, please fix. " myemail@gmail.com < /dev/null
    mv -f /root/tmp/file.txt /var/www/file.txt
fi

Zaletą tego jest to, że dumożna zaakceptować argument do tej opcji w znanym formacie - albo ludzkim, jak w 10K, 10MiBlub czymkolwiek czujesz się komfortowo - nie musisz ręcznie konwertować między formatami / jednostkami, ponieważdu obsługuje to.

Dla odniesienia, oto wyjaśnienie tego SIZEargumentu ze strony podręcznika:

The SIZE argument is an integer and optional unit (example: 10K is 
10*1024). Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers
of 1000). Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
Doron Behar
źródło
+1 Doskonała opcja. Niestety, niektórzy z nas są skazani na starsze wersjedu które go nie obsługują. --thresholdOpcja została dodana w coreutils 8.21, wydany w 2013 roku .
Amit Naidu
1

Okay, jeśli korzystasz z komputera Mac, zrób to: stat -f %z "/Users/Example/config.log" to wszystko!

GarfExiXD
źródło