Як я можу отримати розмір файлу в bash-скрипті?
Як призначити цю змінну bash, щоб я міг її використовувати пізніше?
pv
і cat
для команди копіювання , яка показує прогрес і ETA :)
Як я можу отримати розмір файлу в bash-скрипті?
Як призначити цю змінну bash, щоб я міг її використовувати пізніше?
pv
і cat
для команди копіювання , яка показує прогрес і ETA :)
Відповіді:
Ваша найкраща ставка, якщо в системі GNU:
stat --printf="%s" file.any
Від людини :
% s загальний розмір, у байтах
У базовому сценарії:
#!/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 Jessie ...
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.
Наприклад, "Solaris" кораблі з башем, але не з 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; це не стандартно
Ви також можете скористатися командою "count count" ( 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
наприклад, мають розмір stat, який є лише приблизним , і він 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
: Відображення інформації у вказаному форматі. Дивіться розділ ФОРМАТИ для опису дійсних форматів.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
очевидно, що це найефективніше в цій оболонці.
ГНУstat
(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
.
BSDstat
(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()
«з 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()
є 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
наприклад, мають розміри stat, які є лише приблизними . Це добре для правильності, але погано, якщо кінець файлу знаходиться на диску, а не в пам'яті (особливо, якщо він використовується для багатьох файлів у циклі). І дуже погано, якщо файл буде переміщено до ближнього сховища стрічки або, наприклад, 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-байтних одиниць. GNU du
замість цього використовує кібібайти, якщо тільки не викликається 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
На основі інформації з відповіді @ Stéphane Chazelas.
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. Приклад; малина 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 , щоб "отримати довжину файлу зображення". Я використовую його після того, як роблю змінити файл у Imagemagick, перед відкриттям або повторним завантаженням зображення в переглядач jpeg GUI.
Я не знаю, як це оцінюється як "відповідь", оскільки він позичає багато з того, що вже було запропоновано та обговорено. Тож я залишу його там.
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
відповіді , які повинні мати відмова від відповідальності НІКОЛИ НЕ ЦЕ в реальному житті. Я просто використав свою відповідь у додатку в реальному житті сьогодні ввечері і вважав, що варто поділитися. Я думаю, що всі ми знизуємо свою думку .