Как проверить размер файла с помощью Bash?

148

У меня есть скрипт, который проверяет размер файла 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
user349418
источник
1
unix.stackexchange.com/questions/16640/…
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

258

[ -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

В данном случае это похоже на то, что вы хотите.

Но к вашему сведению, если вы хотите узнать, сколько места на диске использует файл, вы можете использовать его 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 имеют разные флаги.
Mikel
1
Мне пришлось изменить его, чтобы ... | cut -d' ' -f1он работал в Ubuntu.
Mikepote
8
Используйте wc -c < "$file"(обратите внимание на <), и в этом случае вам не нужна эта | cut ...часть (которая, как указано , не работает в OSX). Минимальное BLOCKSIZEзначение для duOSX составляет 512.
mklement0
3
@PetriSirkkala В моей системе Linux wc -c <filenameтакже использует fstatи seek? Обратите внимание, что это fstatпринимает fd, а не путь.
Mikel
27

Меня удивляет, что никто не упомянул 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 заключается в том, что, к сожалению, делает эту альтернативу менее привлекательной. :(
лапо
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
fstab
источник
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на стандартный вывод тогда и только тогда, когда размер file.txtменьше 90 КБ. Чтобы выполнить скрипт, scriptесли file.txtего размер меньше 90 КБ:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
источник
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 говорит: «Reinstate Monica»
1
Вы можете сделать это более эффективным, используя head -c вместо cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; затем эхо «Файл меньше 90 КБ»; fi. Протестировано на CentOS, поэтому может работать или не работать на BSD или OSX.
Кевин Кин,
@BananaNeil, как делать этот процесс каждые 20 секунд, чтобы я мог проверять увеличение размера файла и т. Д.?
A Sahra
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
}
Нил МакГилл
источник
6

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.
Василий Новиков
6
python -c 'import os; print (os.path.getsize("... filename ..."))'

портативный, все разновидности питона, избегает вариаций в диалектах статов

user6336835
источник
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в стандартный вывод тогда и только тогда, когда размер file.txtменьше 90 КБ, и

найдите "file.txt" -size -90k -exec command \;

выполнит команду, commandесли file.txtего размер меньше 90 КБ. Я тестировал это в Linux. От find(1),

… Аргументы командной строки, следующие за ( опции -H, -Lи -P), считаются именами файлов или каталогов, которые нужно исследовать, вплоть до первого аргумента, который начинается с '-', ...

(курсив мой).

G-Man говорит: "Восстановите Монику"
источник
1
ls -l $file | awk '{print $6}'

предполагая, что команда ls сообщает размер файла в столбце №6

Yeugeniuss
источник
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=вариант использования 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

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

Для справки, вот объяснение этого SIZEаргумента на странице руководства:

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" вот и все!

GarfExiXD
источник