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

Bash

Bash Problem Overview


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 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. " [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

Bash Solutions


Solution 1 - Bash

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

Solution 2 - Bash

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?

Solution 3 - Bash

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

Solution 4 - Bash

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

Solution 5 - Bash

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

cat $file | wc -c

Sample output:

> 203233

Solution 6 - Bash

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
}

Solution 7 - Bash

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.

Solution 8 - Bash

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.

Solution 9 - Bash

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

Solution 10 - Bash

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

assuming that ls command reports filesize at column #6

Solution 11 - Bash

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

Solution 12 - Bash

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser349418View Question on Stackoverflow
Solution 1 - BashMikelView Answer on Stackoverflow
Solution 2 - BashDaniel C. SobralView Answer on Stackoverflow
Solution 3 - BashfstabView Answer on Stackoverflow
Solution 4 - Bashgniourf_gniourfView Answer on Stackoverflow
Solution 5 - BashBananaNeilView Answer on Stackoverflow
Solution 6 - BashGoblinhackView Answer on Stackoverflow
Solution 7 - Bashuser6336835View Answer on Stackoverflow
Solution 8 - BashmivkView Answer on Stackoverflow
Solution 9 - BashG-Man Says 'Reinstate Monica'View Answer on Stackoverflow
Solution 10 - BashyeugeniussView Answer on Stackoverflow
Solution 11 - BashGarfExiXDView Answer on Stackoverflow
Solution 12 - BashDoron BeharView Answer on Stackoverflow