it-swarm-vi.com

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

271
haunted85

Đặt cược tốt nhất của bạn nếu trên hệ thống GNU:

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

Từ man stat :

Tổng kích thước% s, tính bằng byte

Trong 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.

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

Vấn đề với việc sử dụng stat là nó là phần mở rộng GNU (Linux). du -kcut -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 rõ ràng. du -h cũng là một 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.

97
Nemo

Bạn cũng có thể sử dụng lệnh "Đếm từ" (wc):

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

Vấn đề với wc là nó sẽ thêm tên tệp và thụt lề đầ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ị bạn đang tìm kiếm dưới dạng biến Shell, như được đề cập bởi Gilles bên dưới.

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

BSD (macOS'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 định dạng đã chỉ định. Xem phần FORMATS để biết mô tả về các định dạng hợp lệ.
  • ... phần ĐỊNH DẠNG ...
  • 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

LƯU Ý: xem câu trả lời của @ b01 để biết cách sử dụng lệnh stat trên các hệ thống GNU/Linux. :)

53
chbrown

Phụ thuộc vào kích thước của bạn .

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 triển khai wc 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 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ố triển khai wc 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))

ksh93wc dựng sẵn (miễn là bạn kích hoạt nó, bạn cũng có thể gọi nó là command /opt/ast/bin/wc) Giúp nó hoạt động hiệu quả nhất cho các tệp thông thường trong Shell đó.

Các hệ thống khác nhau có một lệnh được gọi là stat đó là một giao diện cho các cuộc gọi hệ thống stat() hoặc lstat().

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à thuộc tính st_size. Đố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à cách mà hầu hết các triển khai wc -c Sử dụng trong tối ưu hóa của chúng)). Đối với 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ự cho 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.

Theo thứ tự thời gian, có:

  • IRIX stat (90 giây):

    stat -qLs -- "$file"
    

    trả về thuộc tính st_size của $file (lstat()) hoặc:

    stat -s -- "$file"
    

    tương tự ngoại trừ khi $file là một liên kết tượng trưng trong trường hợp đó là st_size của tệp sau khi phân giải symlink.

  • zshstat buildin (hiện còn được gọi là zstat) trong mô-đun zsh/stat (đượ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 Shell đó.

  • GNU stat (2001); cũng trong BusyBox stat kể 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 được đảo ngược so với IRIX hoặc zshstat.

  • BSD stat (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 hàm stat()/lstat() của một số ngôn ngữ script như Perl:

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

AIX cũng có một lệnh istat sẽ kết xuất tất cả thông tin stat() (không phải lstat(), vì vậy sẽ không hoạt động trên symlink) và mà bạn có thể xử lý hậu kỳ, ví dụ:

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

(cảm ơn @JeffSchaller vì giúp tìm hiểu 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 đó GNU đã giới thiệu lệnh stat, điều tương tự có thể đạt được với lệnh GNU find với lệnh -printf Vị ngữ (đã 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 vị từ find (như !, (. ..).

Lệnh tiêu chuẩn để lấy thông tin stat()/lstat()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 phân giải symlink. Điều đó không làm việc cho các tập tin thiết bị mặc dù 5thứ tự trường 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 trong đó 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ó BLKGETSIZE64ioctl() và hầu hết các bản phân phối Linux hiện có một lệnh blockdev 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. Chẳng hạn (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.

Cách tiếp cận hoạt động cho tất cả các tệp có thể tìm kiếm (bao gồm các tệp thông thường, hầu hết các thiết bị chặn và một số thiết bị ký tự) là mở tệp và tìm đến cuối :

  • Với zsh (sau khi tải mô-đun zsh/system):

    {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() 's 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 FIONREADioctl() 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, việc mở ống chỉ có tên ở đây vẫn có thể có tác dụng phụ. Chúng tôi đang sử dụng fuser để kiểm tra trước rằng một số quy trình đã mở đường ống để 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ề bởi stat()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 tin đượ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 đó).
  • 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

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 thớt đặ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

22
joelparkerhenderson

stat dường như thực hiện điều này với ít cuộc gọi hệ thống 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
9
user150821

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 không đáng tin cậy bằng lệnh stat.

8
Druckles

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 ở định dạng có thể đọc được.

5
Teddy

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.

3
findrbot_admin

Tạo các hàm tiện ích nhỏ trong tập lệnh Shell mà bạn có thể ủy quyền.

Ví 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.

3
oligofren

Một cách khác tuân thủ POSIX sẽ là sử dụng awk với hàm length() 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. Hàm length() trong awk lấy một đối số theo mặc định có nghĩa là length($0) dành cho toàn bộ dòng hiện tại.

0
Inian