Làm cách nào tôi có thể nhận được kích thước của tệp trong tập lệnh bash?
Làm thế nào để tôi gán nó cho một biến bash để tôi có thể sử dụng nó sau này?
pv
và cat
cho một lệnh sao chép hiển thị tiến trình và ETA :)
Làm cách nào tôi có thể nhận được kích thước của tệp trong tập lệnh bash?
Làm thế nào để tôi gán nó cho một biến bash để tôi có thể sử dụng nó sau này?
pv
và cat
cho một lệnh sao chép hiển thị tiến trình và ETA :)
Câu trả lời:
Đặt cược tốt nhất của bạn nếu trên một hệ thống GNU:
stat --printf="%s" file.any
Từ người đàn ông stat :
Tổng kích thước% s, tính bằng byte
Trong một tập lệnh bash:
#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."
LƯU Ý: xem câu trả lời của @ chbrown để biết cách sử dụng stat trong thiết bị đầu cuối trên Mac OS X.
stat
là cách đơn giản nhất, giả sử bạn đang sử dụng Linux hoặc Cygwin ( stat
không phải là tiêu chuẩn). wc -c
theo đề xuất của Eugéne là hàng xách tay.
stat: illegal option -- c
stat --printf="%s" file.txt
không xuất bất cứ thứ gì trên Debian Jessie ...
stat -f%z myfile.tar
man stat
nói rằng --printf bỏ qua dòng mới. Sử dụng --format
hoặc -c
để xem đầu ra. Có được cái nhìn sâu sắc hơn bằng cách so sánh stat --printf="%s" file.any | xxd -
vớistat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
Vấn đề với việc sử dụng stat
là nó là một phần mở rộng GNU (Linux). du -k
và cut -f1
được chỉ định bởi POSIX và do đó có thể di chuyển tới bất kỳ hệ thống Unix nào.
Solaris, ví dụ, tàu có bash nhưng không có stat
. Vì vậy, đây không hoàn toàn là giả thuyết.
ls
có một vấn đề tương tự ở chỗ định dạng chính xác của đầu ra không được chỉ định, do đó việc phân tích cú pháp đầu ra của nó không thể được thực hiện một cách hợp lý. du -h
cũng là một phần mở rộng GNU.
Bám sát các cấu trúc di động nếu có thể, và bạn sẽ làm cho cuộc sống của ai đó dễ dàng hơn trong tương lai. Có lẽ là của riêng bạn.
du
không cho kích thước của tệp, nó cho biết dung lượng tệp sử dụng là bao nhiêu, khác nhau một cách tinh tế (thường kích thước được báo cáo du
là kích thước của tệp được làm tròn đến số khối gần nhất, trong đó một khối thường là 512B hoặc 1kB hoặc 4kB).
--bytes
hoặc -b
thay vì -k
, nên là câu trả lời được chấp nhận.
-h
( "con người") tùy chọndu
sẽ tạo ra câu trả lời thích hợp nhất cho trường hợp tổng quát: file_size=`du -h "$filename" | cut -f1
, vì nó sẽ hiển thị K (kilobyte), M (MB) hoặc G (Gigabyte) cho phù hợp.
Bạn cũng có thể sử dụng lệnh "đếm từ" ( wc
):
wc -c "$filename" | awk '{print $1}'
Vấn đề wc
là nó sẽ thêm tên tệp và thụt đầu ra. Ví dụ:
$ wc -c somefile.txt
1160 somefile.txt
Nếu bạn muốn tránh xâu chuỗi một ngôn ngữ được giải thích đầy đủ hoặc trình chỉnh sửa luồng chỉ để lấy số lượng kích thước tệp, chỉ cần chuyển hướng đầu vào từ tệp để wc
không bao giờ thấy tên tệp:
wc -c < "$filename"
Hình thức cuối cùng này có thể được sử dụng với sự thay thế lệnh để dễ dàng lấy giá trị mà bạn đang tìm kiếm như một biến shell, như được đề cập bởi Gilles dưới đây.
size="$(wc -c <"$filename")"
wc -c <"$FILENAME"
Do đó, cho kích thước không có hành trình khác size=$(wc -c <"$FILENAME")
.
wc -c < file
dường như rất nhanh, ít nhất là trên OS X. Tôi đoán rằng wc có bộ não để cố gắng thống kê tệp nếu chỉ -c được chỉ định.
wc -c
sử dụng fstat
, nhưng sau đó tìm đến khối thứ hai của tệp và đọc các st_blksize
byte cuối cùng . Rõ ràng điều này là do các tệp trong Linux /proc
và /sys
ví dụ có kích thước chỉ gần đúng và wc
muốn báo cáo kích thước thực tế, không phải kích thước được báo cáo theo thống kê. Tôi đoán sẽ là lạ wc -c
khi báo cáo kích thước khác hơn wc
, nhưng không nên đọc dữ liệu từ tệp nếu đó là tệp đĩa bình thường và không có trong bộ nhớ. Hoặc tệ hơn, lưu trữ băng gần tuyến ...
printf
vẫn thấy vết lõm, ví dụ printf "Size: $size"
-> size: <4 spaces> 54339
. Mặt khác echo
bỏ qua khoảng trắng. Bất kỳ cách nào để làm cho nó phù hợp?
fstat
. Hãy thử chạy strace wc -c </etc/passwd
và bạn có thể thấy những gì nó đang làm.
BSD (Mac OS X's) stat
có cờ đối số định dạng khác nhau và các công cụ xác định trường khác nhau. Từ man stat(1)
:
-f format
: Hiển thị thông tin bằng cách sử dụng định dạng được chỉ định. Xem phần FORMATS để biết mô tả về các định dạng hợp lệ.z
: Kích thước của tệp theo byte.Vì vậy, tất cả cùng nhau bây giờ:
stat -f%z myfile1.txt
Phụ thuộc vào những gì bạn có nghĩa là theo kích thước .
size=$(wc -c < "$file")
sẽ cung cấp cho bạn số byte có thể được đọc từ tệp. IOW, đó là kích thước của nội dung của tập tin. Tuy nhiên, nó sẽ đọc nội dung của tệp (trừ khi tệp là tệp thông thường hoặc liên kết tượng trưng đến tệp thông thường trong hầu hết các wc
triển khai dưới dạng tối ưu hóa). Điều đó có thể có tác dụng phụ. Ví dụ, đối với một đường ống có tên, những gì đã đọc không còn có thể được đọc lại và đối với những thứ như /dev/zero
hoặc /dev/random
có kích thước vô hạn, sẽ mất một thời gian. Điều đó cũng có nghĩa là bạn cần có read
quyền đối với tệp và dấu thời gian truy cập cuối cùng của tệp có thể được cập nhật.
Đó là tiêu chuẩn và di động, tuy nhiên lưu ý rằng một số wc
triển khai có thể bao gồm các khoảng trống hàng đầu trong đầu ra đó. Một cách để loại bỏ chúng là sử dụng:
size=$(($(wc -c < "$file")))
hoặc để tránh lỗi về biểu thức số học trống trong dash
hoặc yash
khi wc
không tạo ra đầu ra (như khi tệp không thể mở được):
size=$(($(wc -c < "$file") +0))
ksh93
đã wc
dựng sẵn (miễn là bạn kích hoạt nó, bạn cũng có thể gọi nó dưới dạng command /opt/ast/bin/wc
), điều này làm cho nó hiệu quả nhất đối với các tệp thông thường trong trình bao đó.
Các hệ thống khác nhau có một lệnh được gọi là stat
giao diện cho các cuộc gọi stat()
hoặc lstat()
hệ thống.
Những thông tin báo cáo được tìm thấy trong inode. Một trong những thông tin đó là st_size
thuộc tính. Đối với các tệp thông thường, đó là kích thước của nội dung (có thể đọc được bao nhiêu dữ liệu từ nội dung đó nếu không có lỗi (đó là điều mà hầu hết các wc -c
triển khai sử dụng trong tối ưu hóa của chúng)). Đối với các liên kết tượng trưng, đó là kích thước tính theo byte của đường dẫn đích. Đối với các đường ống được đặt tên, tùy thuộc vào hệ thống, đó là 0 hoặc số byte hiện có trong bộ đệm ống. Tương tự đối với các thiết bị khối trong đó tùy thuộc vào hệ thống, bạn nhận được 0 hoặc kích thước tính theo byte của bộ lưu trữ bên dưới.
Bạn không cần quyền đọc tệp để có được thông tin đó, chỉ có quyền tìm kiếm vào thư mục mà nó được liên kết đến.
Theo thứ tự thời gian, có:
stat -qLs -- "$file"
trả về st_size
thuộc tính của $file
( lstat()
) hoặc:
stat -s -- "$file"
tương tự ngoại trừ khi nào $file
là một liên kết tượng trưng trong trường hợp đó là st_size
tệp sau khi phân giải symlink.
zsh
stat
dựng sẵn (bây giờ còn được gọi là zstat
) trong zsh/stat
mô-đun (được tải với zmodload zsh/stat
) (1997):
stat -L +size -- $file # st_size of file
stat +size -- $file # after symlink resolution
hoặc để lưu trữ trong một biến:
stat -L -A size +size -- $file
rõ ràng, đó là hiệu quả nhất trong vỏ đó.
GNUstat
(2001); cũng trong BusyBox stat
từ năm 2005 (được sao chép từ GNU stat
):
stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
(lưu ý ý nghĩa của -L
đảo ngược so với IRIX hoặc zsh
stat
.
BSDstat
(2002):
stat -f %z -- "$file" # st_size of file
stat -Lf %z -- "$file" # after symlink resolution
Hoặc bạn có thể sử dụng chức năng stat()
/ lstat()
của một số ngôn ngữ kịch bản như perl
:
perl -le 'print((lstat shift)[7])' -- "$file"
AIX cũng có một istat
lệnh sẽ loại bỏ tất cả thông tin stat()
(không lstat()
, vì vậy sẽ không hoạt động trên các liên kết tượng trưng) và bạn có thể xử lý hậu kỳ với, ví dụ:
LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
(cảm ơn @JeffSchaller vì đã giúp tìm ra các chi tiết ).
Trong tcsh
:
@ size = -Z $file:q
(kích thước sau khi phân giải symlink)
Rất lâu trước khi GNU giới thiệu stat
lệnh của mình , điều tương tự có thể đạt được với find
lệnh GNU với -printf
vị từ của nó (đã có vào năm 1991):
find -- "$file" -prune -printf '%s\n' # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution
Tuy nhiên, một vấn đề là nó không hoạt động nếu $file
bắt đầu bằng -
hoặc là một find
vị ngữ (như !
, (
...).
Lệnh tiêu chuẩn để có được stat()
/ lstat()
thông tin là ls
.
POSIXly, bạn có thể làm:
LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
và thêm -L
cho cùng sau khi giải quyết symlink. Điều đó không hoạt động đối với các tệp thiết bị mặc dù trường thứ 5 là số chính của thiết bị thay vì kích thước.
Đối với các thiết bị khối, các hệ thống stat()
trả về 0 cho st_size
, thường có các API khác để báo cáo kích thước của thiết bị khối. Chẳng hạn, Linux có BLKGETSIZE64
ioctl()
và hầu hết các bản phân phối Linux hiện có một blockdev
lệnh có thể sử dụng nó:
blockdev --getsize64 -- "$device_file"
Tuy nhiên, bạn cần có quyền đọc tệp thiết bị cho điều đó. Thông thường có thể lấy kích thước bằng các phương tiện khác. Ví dụ: (vẫn trên Linux):
lsblk -bdno size -- "$device_file"
Nên làm việc ngoại trừ các thiết bị trống.
Một cách tiếp cận mà làm việc cho tất cả seekable file (để bao gồm các file thường xuyên, hầu hết các thiết bị khối và một số thiết bị ký tự) là để mở các tập tin và tìm cách cuối cùng:
Với zsh
(sau khi tải zsh/system
mô-đun):
{sysseek -w end 0 && size=$((systell(0)))} < $file
Với ksh93
:
< "$file" <#((size=EOF))
hoặc là
{ size=$(<#((EOF))); } < "$file"
với perl
:
perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"
Đối với các đường ống được đặt tên, chúng tôi đã thấy rằng một số hệ thống (ít nhất là AIX, Solaris, HP / UX) tạo ra lượng dữ liệu trong bộ đệm ống có sẵn trong stat()
các st_size
. Một số (như Linux hoặc FreeBSD) thì không.
Trên Linux ít nhất, bạn có thể sử dụng FIONREAD
ioctl()
sau khi mở đường ống (ở chế độ đọc + ghi để tránh bị treo):
fuser -s -- "$fifo_file" &&
perl -le 'require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die$!;
print unpack "L", $n' <> "$fifo_file"
Tuy nhiên lưu ý rằng mặc dù nó không đọc nội dung của đường ống, nhưng việc mở đường ống có tên ở đây vẫn có thể có tác dụng phụ. Trước tiên, chúng tôi đang sử dụng fuser
để kiểm tra xem một số quy trình đã có đường ống mở để giảm bớt điều đó nhưng điều đó không thể đánh lừa được vì fuser
có thể không thể kiểm tra tất cả các quy trình.
Bây giờ, cho đến nay chúng tôi chỉ xem xét kích thước của dữ liệu chính được liên kết với các tệp. Điều đó không tính đến kích thước của siêu dữ liệu và tất cả các cơ sở hạ tầng hỗ trợ cần thiết để lưu trữ tệp đó.
Một thuộc tính inode khác được trả về stat()
là st_blocks
. Đó là số khối 512 byte được sử dụng để lưu trữ dữ liệu của tệp (và đôi khi một số siêu dữ liệu của nó như các thuộc tính mở rộng trên hệ thống tệp ext4 trên Linux). Điều đó không bao gồm chính inode hoặc các mục trong thư mục mà tệp được liên kết đến.
Kích thước và mức độ sử dụng đĩa không nhất thiết liên quan chặt chẽ như nén, thưa thớt (đôi khi là một số siêu dữ liệu), cơ sở hạ tầng bổ sung như các khối gián tiếp trong một số hệ thống tệp có ảnh hưởng đến sau này.
Đó thường là những gì du
sử dụng để báo cáo việc sử dụng đĩa. Hầu hết các lệnh được liệt kê ở trên sẽ có thể giúp bạn có được thông tin đó.
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
POSIXLY_CORRECT=1 du -s -- "$file"
(không dành cho các thư mục bao gồm việc sử dụng đĩa của các tệp trong đó).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
sử dụng fstat
, nhưng sau đó đọc các st_blksize
byte cuối cùng . Rõ ràng điều này là do các tệp trong Linux /proc
và /sys
ví dụ có kích thước chỉ tương đương . Điều này tốt cho tính chính xác, nhưng sẽ tệ nếu phần cuối của tệp nằm trên đĩa chứ không phải trong bộ nhớ (đặc biệt nếu được sử dụng trên nhiều tệp trong một vòng lặp). Và rất tệ nếu tệp được di chuyển sang lưu trữ băng gần dòng , hoặc ví dụ hệ thống tệp giải nén trong suốt FUSE.
ls -go file | awk '{print $3}'
-go
sẽ là những người SysV, họ sẽ không hoạt động trên BSD (tùy chọn (XSI) trong POSIX). Bạn cũng cần ls -god file | awk '{print $3; exit}'
( -d
để nó hoạt động trên các thư mục, exit
cho các liên kết tượng trưng với dòng mới trong mục tiêu). Các vấn đề với tập tin thiết bị cũng vẫn còn.
wc -c
báo cáo số lượng byte.
Kịch bản này kết hợp nhiều cách để tính kích thước tệp:
(
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}'
Kịch bản hoạt động trên nhiều hệ thống Unix bao gồm Linux, BSD, OSX, Solaris, SunOS, v.v.
Kích thước tệp hiển thị số byte. Đó là kích thước rõ ràng, là byte mà tệp sử dụng trên một đĩa điển hình, không có nén đặc biệt, hoặc các vùng thưa đặc biệt hoặc các khối không được phân bổ, v.v.
Kịch bản này có phiên bản sản xuất với nhiều trợ giúp hơn và nhiều tùy chọn hơn tại đây: https://github.com/SixArm/file-size
stat xuất hiện để làm điều này với các cuộc gọi hệ thống ít nhất:
$ 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
sẽ cung cấp cho bạn nhiều thông tin về một tệp, bao gồm kích thước tệp, quyền và chủ sở hữu.
Kích thước tệp trong cột thứ năm và được hiển thị theo byte. Trong ví dụ dưới đây, kích thước tệp chỉ dưới 2KB:
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Chỉnh sửa: Điều này rõ ràng là không đáng tin cậy như stat
lệnh.
ls -l
và stat
lệnh cho thông tin kích thước đáng tin cậy. Tôi không tìm thấy bất kỳ tài liệu tham khảo ngược lại. ls -s
sẽ cho kích thước về số lượng khối.
du filename
sẽ cho bạn biết việc sử dụng đĩa theo byte.
Tôi thích du -h filename
, cung cấp cho bạn kích thước trong một định dạng có thể đọc được con người.
du
in ra kích thước trong các khối 1024 byte, không phải là số byte đơn giản.
du
cung cấp một đầu ra với số lượng đơn vị 512 byte. GNU du
sử dụng kibibytes thay vì trừ khi được gọi POSIXLY_CORRECT
trong môi trường của nó.
Tạo các hàm tiện ích nhỏ trong tập lệnh shell của bạn mà bạn có thể ủy quyền.
Thí dụ
#! /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
Dựa trên thông tin từ câu trả lời của @ Stéphane Chazelas.
gzip -v < file > /dev/null
để kiểm tra khả năng nén của tệp.
case
tuyên bố. case
là cấu trúc Bourne / POSIX để thực hiện khớp mẫu. [[...]]
chỉ ksh / bash / zsh (có biến thể).
Tôi đã tìm thấy một lớp lót AWK 1, và nó có một lỗi nhưng tôi đã sửa nó. Tôi cũng đã thêm vào PetaBytes sau 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] }')
Xem xét stat không có trên mọi hệ thống, bạn hầu như luôn có thể sử dụng giải pháp AWK. Thí dụ; Raspberry Pi không có stat nhưng nó có awk .
Một cách khác tuân thủ POSIX sẽ là sử dụng awk
với length()
chức năng của nó trả về độ dài, tính bằng ký tự trên mỗi dòng của tệp đầu vào, ngoại trừ các ký tự dòng mới. Vì vậy, bằng cách làm
awk '{ sum+=length } END { print sum+NR }' file
chúng tôi đảm bảo NR
được thêm vào sum
, do đó dẫn đến tổng số ký tự và tổng số dòng mới gặp trong tệp. Các length()
chức năng trong awk
có một đối số đó bằng phương tiện mặc định length($0)
mà là cho toàn bộ dòng hiện tại.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
nên in 3 nhưng in 4.
Tôi thích tùy chọn wc mình. Được kết hợp với 'bc', bạn có thể nhận được số thập phân đến nhiều nơi bạn muốn.
Tôi đang tìm cách cải thiện một tập lệnh mà tôi đã sử dụng cột 'kích thước tệp' của lệnh 'ls -alh'. Tôi không muốn chỉ có kích thước tệp số nguyên và hai số thập phân có vẻ phù hợp, vì vậy sau khi đọc cuộc thảo luận này, tôi đã đưa ra mã dưới đây.
Tôi đề nghị phá vỡ dòng tại dấu chấm phẩy nếu bạn bao gồm điều này trong một kịch bản.
file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"
Kịch bản của tôi được gọi là gpfl , cho "lấy chiều dài tệp hình ảnh." Tôi sử dụng nó sau khi thực hiện một mogrify trên một tệp trong hình ảnh, trước khi mở hoặc tải lại một hình ảnh trong trình xem jpeg GUI.
Tôi không biết mức giá này như là một "câu trả lời" như thế nào vì nó vay mượn nhiều từ những gì đã được cung cấp và thảo luận. Vì vậy, tôi sẽ để nó ở đó.
BZT
wc
đọc khối cuối cùng của tệp, trong trường hợp stat.st_size
chỉ là một xấp xỉ (như đối với Linux /proc
và /sys
các tệp). Tôi đoán họ đã quyết định không làm cho bình luận chính trở nên phức tạp hơn khi họ thêm logic đó vào một vài dòng: lingrok.org/xref/coreutils/src/wc.c#246
Phương pháp nhanh nhất và đơn giản nhất (IMO) là:
bash_var=$(stat -c %s /path/to/filename)
du
và wc
câu trả lời nên từ chối KHÔNG BAO GIỜ NÀY trong cuộc sống thực. Tôi chỉ sử dụng câu trả lời của mình trong một ứng dụng thực tế tối nay và nghĩ rằng nó đáng để chia sẻ. Tôi đoán tất cả chúng ta có ý kiến của chúng tôi nhún vai .