Как я могу получить размер файла в bash-скрипте?
Как мне присвоить это переменной bash, чтобы я мог использовать ее позже?
pv
и cat
для команды копирования, которая показывает прогресс и ETA :)
Как я могу получить размер файла в bash-скрипте?
Как мне присвоить это переменной bash, чтобы я мог использовать ее позже?
pv
и cat
для команды копирования, которая показывает прогресс и ETA :)
Ответы:
Ваш лучший выбор, если в системе 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.
stat
- самый простой способ, при условии, что вы используете Linux или Cygwin ( stat
не является стандартным). wc -c
как предложено Евгением, является портативным.
stat: illegal option -- c
stat --printf="%s" file.txt
ничего не выводит на Debian, Джесси ...
stat -f%z myfile.tar
man stat
говорит, что --printf пропускает завершающий перевод строки. Используйте --format
или, -c
чтобы увидеть результат. Получить больше понимания путем сравнения stat --printf="%s" file.any | xxd -
сstat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
Проблема с использованием stat
заключается в том, что это расширение GNU (Linux). du -k
и cut -f1
определяются POSIX и поэтому переносимы на любую систему Unix.
Солярис, например, поставляется с Bash, но не с stat
. Так что это не совсем гипотетически.
ls
имеет аналогичную проблему в том, что точный формат вывода не указан, поэтому анализ его вывода не может быть выполнен переносимым. du -h
также расширение GNU.
Придерживайтесь переносных конструкций, где это возможно, и в будущем вы сделаете чью-то жизнь проще. Может быть, ваш собственный.
du
не дает размер файла, он показывает, сколько места занимает файл, что немного отличается (обычно размер, о котором сообщается, du
- это размер файла, округленный до ближайшего числа блоков, где блок обычно составляет 512B или 1kB или 4kB).
--bytes
или -b
вместо -k
, должен быть принятым ответом.
-h
("человек")du
даст наиболее подходящий ответ для общих случаев: file_size=`du -h "$filename" | cut -f1
он будет отображать K (килобайт), M (мегабайт) или G (гигабайт) в зависимости от ситуации.
-h
это расширение GNU; это не стандартно
Вы также можете использовать команду «подсчет слов» ( wc
):
wc -c "$filename" | awk '{print $1}'
Проблема в wc
том, что он добавит имя файла и сделает отступ. Например:
$ wc -c somefile.txt
1160 somefile.txt
Если вы хотите избежать создания цепочки полностью интерпретируемого языка или потокового редактора просто для того, чтобы получить счетчик размера файла, просто перенаправьте ввод из файла, чтобы wc
никогда не видеть имя файла:
wc -c < "$filename"
Эта последняя форма может использоваться с подстановкой команд, чтобы легко получить значение, которое вы искали, как переменную оболочки, как упомянуто Жилем ниже.
size="$(wc -c <"$filename")"
wc -c <"$FILENAME"
таким образом, дает размер без какой-либо другой обработки size=$(wc -c <"$FILENAME")
.
wc -c < file
кажется, очень быстро, по крайней мере, на OS X. Я предполагаю, что у wc есть мозги, чтобы попытаться определить файл, если указан только -c.
wc -c
использует fstat
, но затем ищет второй-последний блок файла и читает последние st_blksize
байты. Очевидно, это связано с тем, что файлы в Linux /proc
и, /sys
например, имеют размеры статистики, которые являются только приблизительными , и wc
хотят сообщить фактический размер, а не размер, указанный в статистике. Я предполагаю, что было бы странно wc -c
сообщать о размере, отличном wc
от указанного, но считывать данные из файла не рекомендуется, если это обычный файл на диске и он не находится в памяти. Или еще хуже, почти линия хранения ленты ...
printf
все еще видит отступ, например printf "Size: $size"
-> size: <4 spaces> 54339
. С другой стороны echo
игнорирует пробелы. Любой способ сделать это последовательным?
fstat
. Попробуйте запустить, strace wc -c </etc/passwd
и вы можете увидеть, что он делает.
У BSD (Mac OS X) stat
есть другой флаг аргумента формата и другие спецификаторы поля. От man stat(1)
:
-f format
: Отображение информации в указанном формате. Смотрите раздел FORMATS для описания допустимых форматов.z
: Размер файла в байтах.Итак, все вместе сейчас:
stat -f%z myfile1.txt
Зависит от того, что вы подразумеваете под размером .
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 или размер в байтах базового хранилища.
Вам не нужно разрешение на чтение файла, чтобы получить эту информацию, только разрешение на поиск в каталоге, с которым он связан.
По хронологическому порядку есть:
IRIXstat
(90-е):
stat -qLs -- "$file"
возвращает st_size
атрибут $file
( lstat()
) или:
stat -s -- "$file"
То же самое, за исключением случаев, когда $file
это символическая ссылка, и в этом случае это st_size
файл после разрешения символической ссылки.
zsh
stat
Встроенный (теперь также известный как 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
очевидно, это самый эффективный в этой оболочке.
GNUstat
(2001); также в BusyBox stat
с 2005 года (скопировано из GNU stat
):
stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
(обратите внимание, что значение -L
обратное по сравнению с IRIX или zsh
stat
.
BSDsstat
(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
команда, которая будет выгружать всю информацию stat()
(нет lstat()
, поэтому не будет работать с символическими ссылками) и которую вы могли бы обработать, например:
LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
(спасибо @JeffSchaller за помощь в выяснении деталей ).
В tcsh
:
@ size = -Z $file:q
(размер после разрешения символической ссылки)
Задолго до того, как GNU представила свою stat
команду, того же можно добиться с помощью find
команды GNU с ее -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 имеет BLKGETSIZE64
ioctl()
, и большинство дистрибутивов 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()
's st_size
. Некоторые (например, Linux или FreeBSD) этого не делают.
По крайней мере, в Linux вы можете использовать FIONREAD
ioctl()
после открытия канала (в режиме чтения + записи, чтобы избежать его зависания):
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()
is st_blocks
. Это количество 512-байтовых блоков, которое используется для хранения данных файла (а иногда и некоторых его метаданных, таких как расширенные атрибуты в файловых системах ext4 в Linux). Это не включает в себя сам индекс или записи в каталогах, с которыми связан файл.
Размер и использование диска не обязательно тесно связаны как сжатие, разреженность (иногда некоторые метаданные), дополнительная инфраструктура, например косвенные блоки в некоторых файловых системах, влияют на последнюю.
Это обычно то, что du
используется, чтобы сообщить об использовании диска. Большинство команд, перечисленных выше, смогут получить эту информацию.
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
POSIXLY_CORRECT=1 du -s -- "$file"
(не для каталогов, где это будет включать в себя использование диска файлов внутри).find -- "$file" -printf '%b\n'
zstat -L +block -- $file
stat -c %b -- "$file"
stat -f %b -- "$file"
perl -le 'print((lstat shift)[12])' -- "$file"
wc -c
использует fstat
, но затем читает последние st_blksize
байты. Очевидно, это потому, что файлы в Linux /proc
и, /sys
например, имеют размеры статистики, которые являются только приблизительными . Это хорошо для корректности, но плохо, если конец файла находится на диске, а не в памяти (особенно, если он используется во многих файлах в цикле). И очень плохо, если файл переносится в ленточное хранилище с близким сроком хранения или, например, в файловую систему с прозрачной декомпрессией FUSE.
ls -go file | awk '{print $3}'
-go
будут SysV, они не будут работать на BSD (опционально (XSI) в POSIX). Вам также понадобится ls -god file | awk '{print $3; exit}'
( -d
для работы с каталогами, exit
для символических ссылок с символами новой строки в цели). Проблемы с файлами устройств также остаются.
wc -c
который сообщает количество байтов.
Этот скрипт объединяет множество способов расчета размера файла:
(
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
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
ls -l filename
предоставит вам много информации о файле, включая его размер, права доступа и владельца.
Размер файла в пятом столбце и отображается в байтах. В приведенном ниже примере размер файла составляет чуть менее 2 КБ:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Изменить: Это, очевидно, не так надежно, как stat
команда.
ls -l
и stat
команда и команда дают достоверную информацию о размере. Я не нашел никаких ссылок на обратное. ls -s
даст размер в количестве блоков.
du filename
скажет вам использование диска в байтах.
Я предпочитаю du -h filename
, который дает вам размер в удобочитаемом формате.
du
выводит размер в блоках по 1024 байта, а не в простое число байтов.
du
дает выход в количестве 512 байт. du
Вместо этого GNU использует кибибайты, если POSIXLY_CORRECT
в своей среде они не вызваны .
Создайте в своих сценариях оболочки небольшие служебные функции, которым вы можете делегировать.
пример
#! /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
Основано на информации из ответа Стефана Шазеля.
gzip -v < file > /dev/null
чтобы проверить сжимаемость файла.
case
утверждение. case
является конструкцией Bourne / POSIX для сопоставления с образцом [[...]]
только ksh / bash / zsh (с вариациями).
Я нашел вкладыш 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] }')
Учитывая, что статистика доступна не для каждой отдельной системы, вы почти всегда можете использовать решение AWK. Пример; у Raspberry Pi нет статов, но есть awk .
Еще один совместимый с POSIX способ заключается в использовании awk
с его length()
функцией, которая возвращает длину, символов в каждой строке входного файла, исключая символы новой строки. Итак, делая
awk '{ sum+=length } END { print sum+NR }' file
мы обеспечиваем NR
добавление к нему sum
, что приводит к общему количеству символов и общему количеству новых строк, встречающихся в файле. length()
Функция awk
принимает которая аргумент с помощью по умолчанию , length($0)
который является для текущей всей линии.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
должно быть напечатано 3, но напечатано 4.
Мне нравится вариант wc сам. В паре с «bc» вы можете получить десятичные знаки в любом количестве мест, где пожелаете.
Я пытался улучшить сценарий, который у меня был, чтобы исключить столбец «размер файла» команды «ls -alh». Я не хотел просто целочисленные размеры файлов, и два десятичных знака, казалось, подходили, поэтому после прочтения этого обсуждения я пришел к приведенному ниже коду.
Я предлагаю разбить строку на точку с запятой, если вы включите это в скрипт.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Мой сценарий называется gpfl , для «получить длину файла изображения». Я использую его после выполнения mogrify для файла в imagemagick, перед открытием или повторной загрузкой изображения в программе просмотра JPEG с графическим интерфейсом.
Я не знаю, как это оценивается как «ответ», поскольку он многое заимствует из того, что уже было предложено и обсуждено. Так что я оставлю это там.
BZT
wc
читает последний блок файла, на случай, если stat.st_size
это только приблизительное значение (как для Linux /proc
и /sys
файлов). Я думаю, что они решили не делать основной комментарий более сложным, когда добавили эту логику на пару строк ниже: lingrok.org/xref/coreutils/src/wc.c#246
Самый быстрый и простой (ИМО) метод это:
bash_var=$(stat -c %s /path/to/filename)
du
и wc
ответы , которые должны иметь отказ от ответственности НИКОГДА НЕ ЭТО в реальной жизни. Сегодня вечером я использовал свой ответ в реальном приложении и подумал, что им стоит поделиться. Я думаю, что у всех нас есть наше мнение пожимает плечами .