Як перевірити розмір файлу за допомогою Bash?


145

У мене є сценарій, який перевіряє розмір 0, але я вважав, що повинен бути простіший спосіб перевірити розміри файлів. Тобто file.txtзазвичай 100 к; як зробити перевірку сценарію, якщо він менше 90 к (включаючи 0), і змусити його зробити нову копію, оскільки файл у цьому випадку пошкоджений.

Що я зараз використовую ..

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

Відповіді:


250

[ -n file.txt ]не перевіряє його розмір, він перевіряє, що рядок file.txtне має нульової довжини, тому він завжди матиме успіх.

Якщо ви хочете сказати, що "розмір не дорівнює нулю", вам потрібно [ -s file.txt ].

Щоб отримати розмір файлу, ви можете wc -cотримати розмір (довжину файлу) у байтах:

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

У цьому випадку це звучить так, що ви хочете.

Але FYI, якщо ви хочете дізнатися, скільки дискового простору використовує файл, ви можете використати du -kдля отримання розміру (використовуваний простір на диску) у кілобайтах:

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

Якщо вам потрібно більше контролювати вихідний формат, ви також можете подивитися stat. У Linux, ви б почати з чим - то начебто stat -c '%s' file.txt, і на BSD / Mac OS X, що - щось на зразок stat -f '%z' file.txt.


5
Чому du -b "$file" | cut -f 1замість stat -c '%s' "$file"? Або stat --printf="%s" "$file"?
mivk

1
Тільки тому, що він більш портативний. BSD та Linux stat мають різні прапори.
Мікель

1
Мені довелося його модифікувати, ... | cut -d' ' -f1щоб змусити його працювати на Ubuntu.
Мікропот

8
Використовуйте wc -c < "$file"(зверніть увагу <), у цьому випадку | cut ...деталь вам не потрібна (яка, як розміщено, не працює на OSX). Мінімальне BLOCKSIZEзначення для duOSX - 512.
mklement0

3
@PetriSirkkala У моїй системі Linux wc -c <filenameтакож використовується fstatі seek? Зауважте, що fstatвикористовується fd, а не ім'я шляху.
Мікель

24

Мене дивує, що ніхто не згадував, statщоб перевірити розмір файлу. Деякі методи, безумовно, кращі: використовувати, -sщоб дізнатися, чи файл порожній чи ні, простіше всього іншого, якщо це все, що ви хочете. І якщо ви хочете знайти файли розміру, то findце, безумовно, шлях.

Мені також дуже подобається duотримати розмір файлу в кб, але, для байтів, я б використовував stat:

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

size=$(stat -c%s $filename) # GNU stat?

2
statце чудова ідея, але на CentOS це те, що працювало для мене:size=$(stat -c%s $filename)
Оз Соломон

2
Різниця між GNU та BSD полягає в тому, що, на жаль, робить цю альтернативу трохи менш привабливою. :(
lapo

1
stat може вводити в оману, якщо файл рідкий. Ви можете використовувати блоки, про які повідомляє stat, для обчислення використовуваного простору.
Аджит Антоній

@AjithAntony Це цікавий момент, який мені не траплявся. Я бачу stat, що в деяких ситуаціях є правильною справою, і розріджені файли не є актуальними у більшості ситуацій, хоча, звичайно, не у всіх.
Даніель К. Собрал

17

альтернативне рішення з awk та подвійними дужками:

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

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi

1
Приємно, але не працює на OSX, де duне підтримується -b. (Це може бути свідомим вибором стилю, але це лише альтернатива: ви можете опустити $префікс всередині (( ... ))при посиланнях на змінні: ((SIZE<90000)))
mklement0

1
Насправді це була редакція попереднього користувача, який вважав, що неправильно пропускати$
fstab

2
@fstab, ви можете пропустити, awkскориставшись read( bashвнутрішня команда):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian

13

Якщо ви findобробляєте цей синтаксис, ви можете використовувати його:

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

Це виведе file.txtдля stdout тоді і тільки тоді, коли розмір file.txtменше 90k. Щоб виконати скрипт, scriptякщо file.txtйого розмір менший 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;

3
+1, але для того, щоб він також працював на OSX, вам потрібен явний аргумент цільового каталогу, наприклад:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0

8

Якщо ви шукаєте лише розмір файлу:

$ cat $file | wc -c
> 203233

1
Це може бути найкоротшою дієвою відповіддю, але це, мабуть, також найповільніше. :)
SunSparc

2
Так, але, безумовно, економічно вищий: Витрати на інженерний час> Вартість часу на обчислення
BananaNeil

8
wc -c "$file"було дано як відповідь у 2011 році (три роки тому). Так, wc -c "$file"є проблема в тому, що він видає ім'я файлу, а також кількість символів, тому до ранніх відповідей додана команда відокремити кількість. Але wc -c < "$file", що вирішує цю проблему, було додано як коментар у травні 2014 року. Ваша відповідь рівнозначна тому, за винятком випадків, коли вона додає «марне використання cat» . Крім того, слід навести всі посилання на змінну оболонки, якщо у вас немає вагомих причин цього не робити.
G-Man каже: "Відновіть Моніку"

1
Ви можете зробити це більш ефективним, використовуючи head -c замість cat.if [$ (head -c 90000 $ файл | wc -c) -lt 90000]; потім відлуння "Файл менше 90 к"; фі. Тестується на CentOS, тому він може працювати або не працювати на BSD або OSX.
Кевін Кін

@BananaNeil як це робити через кожні 20 секунд, щоб я міг перевірити збільшення розміру файлу і так далі?
Сахра

6

Це працює як в Linux, так і в 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 робить це за допомогою найменших системних викликів:

$ 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

Якщо я правильно це розумію, тест слід робити також з перенаправленням труб? strace du --bytes $1 2>&1 >/dev/null | wc Якщо це так, то для архітектури amd64 в ArchLinux (як правило, останні версії всього) у мене є 45 рядків для du, 46 рядків для stat, 47 рядків для wcі 72 рядки для find.
ВасильНовіков

5
python -c 'import os; print (os.path.getsize("... filename ..."))'

портативний, усі аромати пітона, уникає змін у статевих говірках


4

Для отримання розміру файлів як в Linux, так і в Mac OS X (і, імовірно, в інших BSD) існує не так багато варіантів, і більшість запропонованих тут буде працювати лише в одній системі.

Дано f=/path/to/your/file,

що працює в Linux і Mac Bash:

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

або

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

Інші відповіді чудово працюють в Linux, але не в Mac:

  • duне має -bможливості в Mac, і трюк BLOCKSIZE = 1 не працює ("мінімальний розмір блоків 512", що призводить до неправильного результату)

  • cut -d' ' -f1 не працює, тому що на Mac, номер може бути вирівняний праворуч, підкреслений пробілами спереду.

Так що, якщо вам потрібно що - то гнучке, це або perl«s -sоператор або wc -cконвеєр awk '{print $1}'(AWK ігноруватиме провідне білий простір).

І звичайно, стосовно решти оригінального запитання скористайтеся оператором -lt(або -gt):

if [ $size -lt $your_wanted_size ]; then тощо.


3
+1; якщо ви знаєте, що ви будете використовувати розмір лише в арифметичному контексті (де провідна пробіл ігнорується), ви можете спростити size=$(wc -c < "$f")(зверніть увагу <, що призводить wcдо повідомлення лише про число). Порівняння порівняння: не забувайте більше "bash-ful" if (( size < your_wanted_size )); then ...(і також [[ $size -lt $your_wanted_size ]]).
mklement0

3

На основі відповіді gniourf_gniourf,

find "file.txt" -size -90k

буде писати file.txtв stdout тоді і тільки тоді, коли розмір file.txtменше 90K, і

знайдіть "file.txt" -розмір -90k -exec команду \;

виконає команду, commandякщо file.txtвона має розмір менше 90K. Я перевірив це на Linux. З find(1),

... Аргументи командного рядка наступним чином (в -H, -Lі -Pваріанти) приймаються бути імена файлів або каталогів , які будуть розглянуті, до першого аргументу , який починається з «-», ...

(наголос додано).


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

припускаючи, що команда ls повідомляє розмір файлів у стовпці №6


1

Я хотів би використовувати du«S --thresholdдля цього. Не впевнений, чи доступний цей параметр у всіх версіях, duале він реалізований у версії GNU.

Цитуючи посібник від du (1) :

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

Ось моє рішення, використовуючи du --threshold=для випадку використання ОП:

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

Перевагою цього є те, що ви duможете прийняти аргумент на цю опцію у відомому форматі - як людському, так і тому 10K, 10MiBщо коли-небудь вам комфортно - вам не потрібно вручну конвертувати між форматами / одиницями, оскільки це duобробляє.

Для довідки, ось пояснення цього SIZEаргументу зі сторінки man:

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 Відмінний варіант. На жаль, деякі з нас застрягли в старих версіях du, які не підтримують це. --thresholdОпція була додана в Coreutils 8.21, випущена в 2013 році .
Аміт Найду

1

Гаразд, якщо ви на Mac, зробіть це: stat -f %z "/Users/Example/config.log" це все!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.