it-swarm-ru.tech

Как я могу получить размер файла в bash-скрипте?

Как я могу получить размер файла в bash-скрипте?

Как мне присвоить это переменной bash, чтобы я мог использовать ее позже?

271
haunted85

Ваш лучший выбор, если в системе GNU:

stat --printf="%s" file.any

От стат :

% s общий размер, в байтах

В скрипте bash:

#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."

ПРИМЕЧАНИЕ: см. ответ @ chbrown как использовать stat в терминале в Mac OS X.

262
b01
file_size_kb=`du -k "$filename" | cut -f1`

Проблема с использованием stat заключается в том, что это расширение GNU (Linux)). du -k и cut -f1 определены POSIX и поэтому переносимы на любую систему Unix.

Например, Solaris поставляется с bash, но не с stat. Так что это не совсем гипотетически.

ls имеет аналогичную проблему в том, что точный формат вывода не указан, поэтому анализ его вывода не может быть выполнен переносимым. du -h также является расширением GNU.

Придерживайтесь переносных конструкций, где это возможно, и в будущем вы сделаете чью-то жизнь проще. Может быть, ваш собственный.

97
Nemo

Вы также можете использовать команду "Количество слов" (wc):

wc -c "$filename" | awk '{print $1}'

Проблема с wc заключается в том, что он добавит имя файла и сделает отступ. Например:

$ wc -c somefile.txt
    1160 somefile.txt

Если вы хотите избежать создания цепочки полностью интерпретируемого языка или редактора потоков только для того, чтобы получить счетчик размера файла, просто перенаправьте ввод из файла, чтобы wc никогда не видел имя файла:

wc -c < "$filename"

Эта последняя форма может использоваться с подстановкой команд, чтобы легко получить значение, которое вы искали как переменную оболочки, как указано в Gilles ниже.

size="$(wc -c <"$filename")"
79
Eugéne

BSD (macOS) stat имеет другой флаг аргумента формата и другие спецификаторы полей. От man stat(1):

  • -f format: Отображение информации в указанном формате. Смотрите раздел FORMATS для описания допустимых форматов.
  • ... раздел ФОРМАТЫ ...
  • z: размер файла в байтах.

Итак, все вместе сейчас:

stat -f%z myfile1.txt

ПРИМЕЧАНИЕ. См. ответ @ b01 , чтобы узнать, как использовать команду stat в системах GNU/Linux. :)

53
chbrown

Зависит от того, что вы подразумеваете под размером .

size=$(wc -c < "$file")

даст вам количество байтов, которые можно прочитать из файла. IOW, это размер содержимого файла. Однако он будет читать содержимое файла (за исключением случаев, когда файл является обычным файлом или символической ссылкой на обычный файл в большинстве реализаций wc в качестве оптимизации). Это может иметь побочные эффекты. Например, для именованного канала прочитанное больше не может быть прочитано снова, а для таких вещей, как /dev/zero или /dev/random, которые имеют бесконечный размер, потребуется некоторое время. Это также означает, что вам нужно read разрешение на файл, и отметка времени последнего доступа файла может быть обновлена.

Это стандартно и переносимо, однако обратите внимание, что некоторые реализации wc могут включать начальные пробелы в этом выводе. Один из способов избавиться от них - использовать:

size=$(($(wc -c < "$file")))

или чтобы избежать ошибки о пустом арифметическом выражении в dash или yash, когда wc не выдает выходных данных (например, когда файл не может быть открыт):

size=$(($(wc -c < "$file") +0))

ksh93 имеет встроенный wc (при условии, что вы включите его, вы также можете вызвать его как command /opt/ast/bin/wc), что делает его наиболее эффективным для обычных файлов в этой оболочке.

Различные системы имеют команду stat, которая является интерфейсом системных вызовов stat() или lstat().

Те сообщают информацию, найденную в inode. Одной из этих сведений является атрибут st_size. Для обычных файлов это размер содержимого (сколько данных можно прочитать из него при отсутствии ошибок (именно это большинство реализаций wc -c используют при оптимизации)). Для символических ссылок это размер в байтах целевого пути. Для именованных каналов, в зависимости от системы, это либо 0, либо количество байтов, находящихся в данный момент в буфере канала. То же самое для блочных устройств, где в зависимости от системы вы получаете 0 или размер в байтах базового хранилища.

Вам не нужно разрешение на чтение файла, чтобы получить эту информацию, только разрешение на поиск в каталоге, с которым он связан.

По хронологическому порядку есть:

  • IRIX stat (90-е):

    stat -qLs -- "$file"
    

    возвращает атрибут st_size$file (lstat()) или:

    stat -s -- "$file"
    

    то же самое, за исключением случаев, когда $file является символической ссылкой, в этом случае это st_size файла после разрешения символической ссылки.

  • zshstat встроенный (теперь также известный как zstat) в модуле zsh/stat (загружен с zmodload zsh/stat) (1997):

    stat -L +size -- $file # st_size of file
    stat +size -- $file    # after symlink resolution
    

    или хранить в переменной:

    stat -L -A size +size -- $file
    

    очевидно, это самый эффективный в этой оболочке.

  • GNU stat (2001); также в BusyBox stat с 2005 года (скопировано из GNU stat):

    stat -c %s -- "$file"  # st_size of file
    stat -Lc %s -- "$file" # after symlink resolution
    

    (обратите внимание, что значение -L обратное по сравнению с IRIX или zshstat.

  • BSDs stat (2002):

    stat -f %z -- "$file"  # st_size of file
    stat -Lf %z -- "$file" # after symlink resolution
    

Или вы можете использовать функцию stat()/lstat() некоторого языка сценариев, например Perl:

Perl -le 'print((lstat shift)[7])' -- "$file"

AIX также имеет istat command , которая будет сбрасывать всю информацию stat() (не lstat(), поэтому не будет работать с символическими ссылками) и который вы могли бы обработать, например:

LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'

(спасибо @JeffSchaller за помогите разобраться в деталях ).

В tcsh:

@ size = -Z $file:q

(размер после разрешения символической ссылки)

Задолго до того, как GNU представило свою команду stat, того же можно добиться с помощью команды GNU find с предикатом -printf) ( уже в 1991 году)

find -- "$file" -Prune -printf '%s\n'    # st_size of file
find -L -- "$file" -Prune -printf '%s\n' # after symlink resolution

Однако одна проблема заключается в том, что не работает, если $file начинается с - или является предикатом find (например, !, (...).

Стандартная команда для получения информации stat()/lstat()ls.

POSIXly, вы можете сделать:

LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'

и добавьте -L для того же самого после разрешения символической ссылки. Это не работает для файлов устройств, хотя где 5го поле - это основной номер устройства, а не размер.

Для блочных устройств системы, в которых stat() возвращает 0 для st_size, обычно имеют другие API для сообщения о размере блочного устройства. Например, в Linux есть BLKGETSIZE64ioctl(), и большинство дистрибутивов Linux теперь поставляются с командой blockdev, которая может использовать ее:

blockdev --getsize64 -- "$device_file"

Однако для этого вам нужно разрешение на чтение файла устройства. Обычно можно получить размер другими способами. Например (все еще в Linux):

lsblk -bdno size -- "$device_file"

Должно работать за исключением пустых устройств.

Подход, который работает для всех файлов с возможностью поиска (включая обычные файлы, большинство блочных устройств и некоторые символьные устройства), заключается в открытии файла и поиске до конца. :

  • С zsh (после загрузки модуля zsh/system):

    {sysseek -w end 0 && size=$((systell(0)))} < $file
    
  • С ksh93:

    < "$file" <#((size=EOF))
    

    или

    { size=$(<#((EOF))); } < "$file"
    
  • с Perl:

    Perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"
    

Для именованных каналов мы видели, что некоторые системы (по крайней мере, AIX, Solaris, HP/UX) предоставляют объем данных в буфере канала, доступный в stat()st_size. Некоторые (например, Linux или FreeBSD) этого не делают.

По крайней мере, в Linux вы можете использовать FIONREADioctl() после открытия канала (в режиме чтения + записи, чтобы избежать его зависания):

fuser -s -- "$fifo_file" && 
  Perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &FIONREAD, $n) or die$!;
            print unpack "L", $n' <> "$fifo_file"

Однако обратите внимание, что хотя он не читает содержимое канала, простое открытие именованного канала может иметь побочные эффекты. Мы используем fuser, чтобы сначала проверить, что у какого-то процесса уже есть открытый канал, чтобы облегчить это, но это не надежно, поскольку fuser не сможет проверить все процессы.

Итак, до сих пор мы рассматривали только размер первичных данных, связанных с файлами. Это не учитывает размер метаданных и всю вспомогательную инфраструктуру, необходимую для хранения этого файла.

Другой атрибут inode, возвращаемый stat(), это st_blocks. Это количество блоков размером 512 байт, которое используется для хранения данных файла (а иногда и некоторых его метаданных, таких как расширенные атрибуты в файловых системах ext4 в Linux). Это не включает сам индекс, или записи в каталогах, с которыми связан файл.

Размер и использование диска не обязательно тесно связаны как сжатие, разреженность (иногда некоторые метаданные), дополнительная инфраструктура, например косвенные блоки в некоторых файловых системах, влияют на последнюю.

Это обычно то, что du использует, чтобы сообщить об использовании диска. Большинство команд, перечисленных выше, смогут получить эту информацию.

  • POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
  • POSIXLY_CORRECT=1 du -s -- "$file" (не для каталогов, где это будет включать в себя использование диска файлов внутри).
  • GNU find -- "$file" -printf '%b\n'
  • zstat -L +block -- $file
  • GNU stat -c %b -- "$file"
  • BSD stat -f %b -- "$file"
  • Perl -le 'print((lstat shift)[12])' -- "$file"
32
Stéphane Chazelas

Этот скрипт объединяет множество способов расчета размера файла:

(
  du --apparent-size --block-size=1 "$file" 2>/dev/null ||
  gdu --apparent-size --block-size=1 "$file" 2>/dev/null ||
  find "$file" -printf "%s" 2>/dev/null ||
  gfind "$file" -printf "%s" 2>/dev/null ||
  stat --printf="%s" "$file" 2>/dev/null ||
  stat -f%z "$file" 2>/dev/null ||
  wc -c <"$file" 2>/dev/null
) | awk '{print $1}'

Скрипт работает во многих системах Unix, включая Linux, BSD, OSX, Solaris, SunOS и т.д.

Размер файла показывает количество байтов. Это очевидный размер, который представляет собой байты, которые файл использует на типичном диске, без специального сжатия, специальных разреженных областей, нераспределенных блоков и т.д.

Этот скрипт имеет производственную версию с дополнительной справкой и дополнительными опциями здесь: https://github.com/SixArm/file-size

22
joelparkerhenderson

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
9
user150821

ls -l filename предоставит вам много информации о файле, включая его размер, права доступа и владельца.

Размер файла в пятом столбце и отображается в байтах. В приведенном ниже примере размер файла составляет чуть менее 2 КБ:

-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php

Edit: Это, очевидно, не так надежно, как команда stat.

8
Druckles

du filename сообщит вам об использовании диска в байтах.

Я предпочитаю du -h filename, который дает вам размер в удобочитаемом формате.

5
Teddy

Я нашел вкладыш AWK 1, и в нем была ошибка, но я исправил ее. Я также добавил в PetaBytes после TeraBytes.

FILE_SIZE=234234 # FILESIZE IN BYTES
FILE_SIZE=$(echo "${FILE_SIZE}" | awk '{ split( "B KB MB GB TB PB" , v ); s=1; while( $1>1024 ){ $1/=1024; s++ } printf "%.2f %s", $1, v[s] }')

Учитывая, что stat не в каждой системе, вы почти всегда можете использовать решение AWK. Пример; Raspberry Pi не имеет stat, но имеет awk.

3
findrbot_admin

Создайте в своих сценариях Shell небольшие служебные функции, которым вы можете делегировать.

пример

#! /bin/sh -
# vim: set ft=sh

# size utility that works on GNU and BSD systems
size(){
    case $(uname) in
        (Darwin | *BSD*)
            stat -Lf %z -- "$1";;
        (*) stat -c %s -- "$1"
    esac
}

for f do
    printf '%s\n' "$f : $(gzip < "$f" | wc -c) bytes (versus $(size "$f") bytes)"
done

Основано на информации из ответа Стефана Шазеля.

3
oligofren

Еще один способ, совместимый с POSIX, заключается в использовании awk с его функцией length(), которая возвращает длину в символах в каждой строке входного файла, исключая символы новой строки. Итак, делая

_awk '{ sum+=length } END { print sum+NR }' file
_

мы гарантируем, что NR добавляется к sum, что приводит к общему количеству символов и общему количеству строк, встречающихся в файле. Функция length() в awk принимает аргумент, который по умолчанию означает length($0) для текущей целой строки.

0
Inian