开发者

How can I check the size of a file using Bash?

I've got a script that checks for 0-size, but I thought there must be an easier way to check for file s开发者_运维技巧izes instead. I.e. file.txt is normally 100 kB; how can I make a script check if it is less than 90 kB (including 0), and make it Wget a new copy because the file is corrupt in this case?

What I'm currently using...

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


[ -n file.txt ] doesn't check its size. It checks that the string file.txt is non-zero length, so it will always succeed.

If you want to say "size is non-zero", you need [ -s file.txt ].

To get a file's size, you can use wc -c to get the size (file length) in bytes:

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

In this case, it sounds like that's what you want.

But FYI, if you want to know how much disk space the file is using, you could use du -k to get the size (disk space used) in kilobytes:

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

If you need more control over the output format, you can also look at stat. On Linux, you'd start with something like stat -c '%s' file.txt, and on BSD and Mac OS X, something like stat -f '%z' file.txt.


stat can also check the file size. Some methods are definitely better: using -s to find out whether the file is empty or not is easier than anything else if that's all you want. And if you want to find files of a size, then find is certainly the way to go.

I also like du a lot to get file size in kb, but, for bytes, I'd use stat:

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

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


An alternative solution with AWK and double parenthesis:

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

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


If your find handles this syntax, you can use it:

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

This will output file.txt to stdout if and only if the size of file.txt is less than 90k. To execute a script script if file.txt has a size less than 90k:

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


If you are looking for just the size of a file:

cat $file | wc -c

Sample output:

203233


This works in both Linux and 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
}


Use:

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

It is portable, for all flavours of Python, and it avoids variation in stat dialects.


For getting the file size in both Linux and Mac OS X (and presumably other BSD systems), there are not many options, and most of the ones suggested here will only work on one system.

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

what does work in both Linux and Mac's Bash:

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

or

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

The other answers work fine in Linux, but not in Mac:

  • du doesn't have a -b option in Mac, and the BLOCKSIZE=1 trick doesn't work ("minimum blocksize is 512", which leads to a wrong result)

  • cut -d' ' -f1 doesn't work because on Mac, the number may be right-aligned, padded with spaces in front.

So if you need something flexible, it's either perl's -s operator , or wc -c piped to awk '{print $1}' (awk will ignore the leading white space).

And of course, regarding the rest of your original question, use the -lt (or -gt) operator:

if [ $size -lt $your_wanted_size ]; then, etc.


Based on gniourf_gniourf’s answer,

find "file.txt" -size -90k

will write file.txt to stdout if and only if the size of file.txt is less than 90K, and

find "file.txt" -size -90k -exec command \;

will execute the command command if file.txt has a size less than 90K.  I have tested this on Linux.  From find(1),

…  Command-line arguments following (the -H, -L and -P options) are taken to be names of files or directories to be examined, up to the first argument that begins with ‘-’, …

(emphasis added).


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

assuming that ls command reports filesize at column #6


I would use du's --threshold for this. Not sure if this option is available in all versions of du but it is implemented in GNU's version.

Quoting from du(1)'s manual:

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

Here's my solution, using du --threshold= for OP's use case:

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

The advantage of that, is that du can accept an argument to that option in a known format - either human as in 10K, 10MiB or what ever you feel comfortable with - you don't need to manually convert between formats / units since du handles that.

For reference, here's the explanation on this SIZE argument from the man page:

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.


Okay, if you're on a Mac, do this: stat -f %z "/Users/Example/config.log" That's it!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜