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

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.


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?

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

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 \;

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

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
}

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

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


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.


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).


1
ls -l $file | awk '{print $6}'

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


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.

+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!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.