Làm cách nào để kiểm tra kích thước của tệp bằng Bash?


145

Tôi đã có một tập lệnh kiểm tra kích thước 0, nhưng tôi nghĩ rằng phải có một cách dễ dàng hơn để kiểm tra kích thước tệp thay thế. Tức file.txtlà bình thường 100k; làm thế nào để tạo một kịch bản kiểm tra nếu nó nhỏ hơn 90k (bao gồm 0) và làm cho nó không sao chép một bản sao mới vì tệp này bị hỏng trong trường hợp này.

Những gì tôi đang sử dụng ..

if [ -n file.txt ]
then
 echo "everything is good"
else
 mail -s "file.txt size is zero, please fix. " myemail@gmail.com < /dev/null
 # Grab wget as a fallback 
 wget -c https://www.server.org/file.txt -P /root/tmp --output-document=/root/tmp/file.txt
 mv -f /root/tmp/file.txt /var/www/file.txt
fi

Câu trả lời:


250

[ -n file.txt ]không kiểm tra kích thước của nó, nó kiểm tra xem chuỗi file.txtcó độ dài khác không, vì vậy nó sẽ luôn thành công.

Nếu bạn muốn nói "kích thước là khác không", bạn cần [ -s file.txt ].

Để có được kích thước của tệp, bạn có thể sử dụng wc -cđể lấy kích thước (độ dài tệp) theo byte:

file=file.txt
minimumsize=90000
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi

Trong trường hợp này, có vẻ như đó là những gì bạn muốn.

Nhưng FYI, nếu bạn muốn biết tệp đang sử dụng bao nhiêu dung lượng đĩa, bạn có thể sử dụng du -kđể lấy kích thước (dung lượng đĩa được sử dụng) tính bằng kilobyte:

file=file.txt
minimumsize=90
actualsize=$(du -k "$file" | cut -f 1)
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize kilobytes
else
    echo size is under $minimumsize kilobytes
fi

Nếu bạn cần kiểm soát nhiều hơn định dạng đầu ra, bạn cũng có thể xem xét stat. Trên Linux, bạn sẽ bắt đầu với một cái gì đó như stat -c '%s' file.txt, và trên BSD / Mac OS X, một cái gì đó như stat -f '%z' file.txt.


5
Tại sao du -b "$file" | cut -f 1thay vì stat -c '%s' "$file"? Hay là stat --printf="%s" "$file"?
mivk 14/12/13

1
Chỉ bởi vì nó di động hơn. BSD và Linux stat có các cờ khác nhau.
Mikel

1
Tôi đã phải sửa đổi nó để ... | cut -d' ' -f1làm cho nó hoạt động trên Ubuntu.
Mikepote

8
Sử dụng wc -c < "$file"(lưu ý <), trong trường hợp bạn không cần | cut ...phần (mà, như đã đăng, không hoạt động trên OSX). BLOCKSIZEGiá trị tối thiểu cho dutrên OSX là 512.
mkuity0

3
@PetriSirkkala Trên hệ thống Linux của tôi, wc -c <filenamecũng sử dụng fstatseek? Lưu ý rằng fstatcó một fd, không phải là một tên đường dẫn.
Mikel

24

Nó làm tôi ngạc nhiên rằng không ai đề cập statđến để kiểm tra kích thước tập tin. Một số phương pháp chắc chắn tốt hơn: sử dụng -sđể tìm hiểu xem tệp có trống hay không dễ dàng hơn bất kỳ thứ gì khác nếu đó là tất cả những gì bạn muốn. Và nếu bạn muốn tìm các tập tin có kích thước, thì findchắc chắn là cách để đi.

Tôi cũng thích durất nhiều để có được kích thước tệp trong kb, nhưng, đối với byte, tôi sẽ sử dụng stat:

size=$(stat -f%z $filename) # BSD stat

size=$(stat -c%s $filename) # GNU stat?

2
statlà một ý tưởng tuyệt vời, nhưng trên CentOS, đây là điều làm việc cho tôi:size=$(stat -c%s $filename)
Oz Solomon

2
Sự khác biệt giữa GNU và BSD là điều không may làm cho sự thay thế này kém hấp dẫn hơn một chút. :(
lapo

1
stat có thể gây hiểu nhầm nếu tập tin thưa thớt. Bạn có thể sử dụng các khối được báo cáo bởi stat để tính toán không gian sử dụng.
Ajith Antony

@AjithAntony Đó là một điểm thú vị không xảy ra với tôi. Tôi có thể thấy statlà điều đúng đắn trong một số tình huống và các tệp thưa thớt không liên quan trong hầu hết các tình huống, mặc dù chắc chắn không phải tất cả.
Daniel C. Sobral

17

giải pháp thay thế với awk và dấu ngoặc kép:

FILENAME=file.txt
SIZE=$(du -sb $FILENAME | awk '{ print $1 }')

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi

1
Đẹp, nhưng sẽ không hoạt động trên OSX, nơi dukhông hỗ trợ -b. (Nó có thể là một lựa chọn phong cách có ý thức, nhưng chỉ cần đề cập đến phương án thay thế: bạn có thể bỏ qua $tiền tố bên trong (( ... ))khi tham chiếu các biến ((SIZE<90000)):)
mkuity0

1
Trên thực tế, đó là một chỉnh sửa từ một người dùng trước đó đã nghĩ rằng đã bỏ qua$
fstab

2
@fstab, bạn có thể awksử dụng bằng cách sử dụng read( bashlệnh nội bộ):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian

13

Nếu bạn findxử lý cú pháp này, bạn có thể sử dụng nó:

find -maxdepth 1 -name "file.txt" -size -90k

Điều này sẽ xuất ra file.txtthiết bị xuất chuẩn khi và chỉ khi kích thước file.txtnhỏ hơn 90k. Để thực thi tập lệnh scriptnếu file.txtcó kích thước nhỏ hơn 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;

3
+1, nhưng để làm cho nó hoạt động trên OSX, bạn cần một đối số thư mục đích rõ ràng, ví dụ:find . -maxdepth 1 -name "file.txt" -size -90k
mkuity0

8

Nếu bạn đang tìm kiếm kích thước của một tập tin:

$ cat $file | wc -c
> 203233

1
Đây có thể là câu trả lời khả thi ngắn nhất, nhưng có lẽ cũng chậm nhất. :)
SunSparc

2
Có, nhưng chắc chắn vượt trội về kinh tế: Chi phí thời gian kỹ thuật> Chi phí thời gian tính toán
BananaNeil

8
wc -c "$file"đã được đưa ra như một câu trả lời vào năm 2011 (ba năm trước). Có, wc -c "$file"có vấn đề là nó xuất ra tên tệp cũng như số ký tự, vì vậy các câu trả lời sớm đã thêm một lệnh để tách số đếm. Nhưng wc -c < "$file", mà bản sửa lỗi vấn đề, đã được bổ sung như một bình luận Tháng Năm 2014. Câu trả lời của bạn là tương đương với đó, ngoại trừ nó cho biết thêm một “sử dụng vô dụng của cat . Ngoài ra, bạn nên trích dẫn tất cả các tham chiếu biến shell trừ khi bạn có lý do chính đáng để không.
G-Man nói 'Phục hồi Monica'

1
Bạn có thể thực hiện việc này hiệu quả hơn bằng cách sử dụng head -c thay vì cat.if [$ (head -c 90000 $ file | wc -c) -lt 90000]; sau đó lặp lại "Tệp nhỏ hơn 90k"; bốc lửa Đã thử nghiệm trên CentOS, do đó, nó có thể hoặc không hoạt động trên BSD hoặc OSX.
Kevin Keane

@BananaNeil làm thế nào để thực hiện quá trình này mỗi 20 giây để tôi có thể kiểm tra tăng kích thước tệp như vậy?
Một Sahra

6

Điều này hoạt động trong cả linux và macos

function filesize
{
    local file=$1
    size=`stat -c%s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]
    then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]
    then
        echo $st_size
        return 0
    fi

    return -1
}

5

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

Nếu tôi hiểu chính xác, thử nghiệm cũng nên được thực hiện với chuyển hướng ống?: strace du --bytes $1 2>&1 >/dev/null | wc Nếu đó là trường hợp, thì trên kiến ​​trúc amd64 trên ArchLinux (thường là phiên bản mới nhất của mọi thứ) Tôi có 45 dòng cho du, 46 dòng cho stat, 47 dòng cho wcvà 47 dòng cho và 47 dòng cho và 47 dòng cho 72 dòng cho find.
VasiliNovikov

5
python -c 'import os; print (os.path.getsize("... filename ..."))'

di động, tất cả các hương vị của trăn, tránh sự thay đổi trong phương ngữ stat


4

Để có được kích thước tệp trong cả Linux và Mac OS X (và có lẽ là các BSD khác), không có nhiều tùy chọn và hầu hết các tùy chọn được đề xuất ở đây sẽ chỉ hoạt động trên một hệ thống.

Cho f=/path/to/your/file,

những gì hoạt động trong cả Bash của Linux và Mac :

size=$( perl -e 'print -s shift' "$f" )

hoặc là

size=$( wc -c "$f" | awk '{print $1}' )

Các câu trả lời khác hoạt động tốt trong Linux, nhưng không phải trong Mac:

  • dukhông có -btùy chọn trong Mac và thủ thuật BLOCKSIZE = 1 không hoạt động ("chặn tối thiểu là 512", dẫn đến kết quả sai)

  • cut -d' ' -f1 không hoạt động vì trên Mac, số có thể được căn phải, được đệm bằng khoảng trắng ở phía trước.

Vì vậy, nếu bạn cần một cái gì đó linh hoạt, thì đó perl-stoán tử hoặc wc -cđược chuyển sang awk '{print $1}'(awk sẽ bỏ qua khoảng trắng hàng đầu).

Và tất nhiên, liên quan đến phần còn lại của câu hỏi ban đầu của bạn, hãy sử dụng toán tử -lt(hoặc -gt):

if [ $size -lt $your_wanted_size ]; then Vân vân.


3
+1; nếu bạn biết bạn sẽ chỉ sử dụng kích thước trong ngữ cảnh số học (trong đó khoảng trắng hàng đầu bị bỏ qua), bạn có thể đơn giản hóa size=$(wc -c < "$f")(lưu ý <, nguyên nhân wcchỉ báo cáo một số). So sánh lại: đừng quên nhiều "bash-Ful" if (( size < your_wanted_size )); then ...(và cả [[ $size -lt $your_wanted_size ]]).
mkuity0

3

Dựa trên câu trả lời của gniourf_gniourf,

find "file.txt" -size -90k

sẽ ghi file.txtvào thiết bị xuất chuẩn khi và chỉ khi kích thước file.txtnhỏ hơn 90K và

tìm "file.txt" -size -90k -exec lệnh \;

sẽ thực thi lệnh commandnếu file.txtcó kích thước nhỏ hơn 90K. Tôi đã thử nghiệm điều này trên Linux. Từ find(1),

... đối số dòng lệnh sau đây (các -H, -L-Ptùy chọn) đều được đưa đến là tên của tập tin hoặc thư mục để được kiểm tra, lên đến đối số đầu tiên bắt đầu với '-', ...

(nhấn mạnh thêm).


1
ls -l $file | awk '{print $6}'

giả sử rằng lệnh ls báo cáo kích thước tập tin ở cột số 6


1

Tôi sẽ sử dụng du's --thresholdcho việc này. Không chắc tùy chọn này có sẵn trong tất cả các phiên bản hay không dunhưng nó được triển khai trong phiên bản GNU.

Trích dẫn từ hướng dẫn của du (1) :

-t, --threshold=SIZE
       exclude entries smaller than SIZE if positive, or entries greater
       than SIZE if negative

Đây là giải pháp của tôi, sử dụng du --threshold=cho trường hợp sử dụng của OP:

THRESHOLD=90k
if [[ -z "$(du --threshold=${THRESHOLD} file.txt)" ]]; then
    mail -s "file.txt size is below ${THRESHOLD}, please fix. " myemail@gmail.com < /dev/null
    mv -f /root/tmp/file.txt /var/www/file.txt
fi

Ưu điểm của việc đó, là ducó thể chấp nhận một cuộc tranh cãi để tùy chọn đó trong một định dạng được biết đến - một trong hai con người như trong 10K, 10MiBhoặc những gì đã bao giờ bạn cảm thấy thoải mái với - bạn không cần phải chuyển đổi giữa các định dạng bằng tay / đơn vị kể từ khi duxử lý đó.

Để tham khảo, đây là lời giải thích về SIZElập luận này từ trang man:

The SIZE argument is an integer and optional unit (example: 10K is 
10*1024). Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers
of 1000). Binary prefixes can be used, too: KiB=K, MiB=M, and so on.

+1 Tùy chọn tuyệt vời. Thật không may, một số người trong chúng ta bị mắc kẹt với các phiên bản cũ hơn dukhông hỗ trợ nó. Các --thresholdtùy chọn được thêm vào trong coreutils 8,21, phát hành vào năm 2013 .
Amit N Nikol

1

Được rồi, nếu bạn đang dùng Mac, hãy làm điều này: stat -f %z "/Users/Example/config.log" Đó là nó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.