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.