[bash] How to check 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 sizes instead. I.e. file.txt is normally 100k; how to make a script check if it is less than 90k (including 0), and make it do 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. " [email protected] < /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

This question is related to bash

The answer is


For getting the file size in both Linux and Mac OS X (and presumably other BSDs), 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.


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. " [email protected] < /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.

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
}

stat appears to do this with the fewest system calls:

$ 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

It surprises me that no one mentioned stat to check 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?

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

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


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

portable, all flavours of python, avoids variation in stat dialects


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 \;

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


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

$ cat $file | wc -c
> 203233

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

assuming that ls command reports filesize at column #6