319

I have a file called diff.txt. I Want to check whether it is empty.

I wrote a bash script something like below, but I couldn't get it work.

if [ -s diff.txt ]
then
        touch empty.txt
        rm full.txt
else
        touch full.txt
        rm emtpy.txt
fi
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
Mich
  • 3,253
  • 2
  • 14
  • 6
  • 47
    [ -s FILE ] True if FILE exists and has a size greater than zero. Thus, you get "empty.txt" if "diff.txt" is not empty. – Matthias Apr 01 '12 at 13:48
  • 3
    PS: If you want to check an actual `diff` call, just check the return value: `if diff foo.txt bar.txt; then echo 'No difference'` – l0b0 Apr 02 '12 at 13:13
  • 36
    Test can be negated: `if [ ! -s diff.txt ]; then echo "IS EMPTY";else echo "HAS SOMETHING";fi` – David Ramirez Jun 13 '14 at 20:44
  • 1
    Beware of the trailing new-line characters. Check the file out with `$ cat diff.txt | hexdump -C` – Alejandro Blasco Feb 20 '18 at 15:18
  • @DavidRamirez: Note, that `[ … ]` is different from bash’s native `[[ … ]]`, in that the latter allows some things that would break the former. E.g. w.r.t. quoting or comparison operators. – Evi1M4chine Jan 01 '23 at 17:42

12 Answers12

389

try this:

#!/bin/bash -e

if [ -s diff.txt ]; then
        # The file is not-empty.
        rm -f empty.txt
        touch full.txt
else
        # The file is empty.
        rm -f full.txt
        touch empty.txt
fi

Notice incidentally, that I have swapped the roles of empty.txt and full.txt, as @Matthias suggests.

hoijui
  • 3,615
  • 2
  • 33
  • 41
thb
  • 13,796
  • 3
  • 40
  • 68
  • 13
    The shell can help with misspellings. `empty=empty.txt; full=full.txt; diff=diff.txt; if [ -s ${diff?} ]; then r=${empty?} t=${full?}; else r=${full?} t=${empty?}; fi; rm ${r?}; touch ${t?}` – William Pursell Sep 13 '16 at 15:31
  • 4
    Using the tool shellcheck can find spelling errors just fine. – Yokai Oct 03 '16 at 03:30
  • 1
    Surely this will fail if the file does not exist either? This is supposed to be a check if the file is empty only. – geedoubleya Oct 05 '17 at 11:31
  • @geedoubleya: Sure. That's a reasonable point. If the file's existence were relevant (as, of course, it might be), then one might adjust the script accordingly. If you gave the adjusted script as an *answer* and pinged me, I'd upvote. – thb Oct 10 '17 at 15:08
  • I think a better example can be used here, more precisely change full.txt and empty.txt to something that makes more sense to what is being checked ... I am tempted to downvote, – Mike Q Apr 29 '18 at 18:24
  • 2
    You can also `set -u` – Jon McClung Aug 20 '19 at 19:54
  • @WilliamPursell, is '?' for in ${word?} ? – Erwann Aug 02 '20 at 01:48
  • @Erwann I do not understand your question. When the shell evaluates `${word?}`, it throws an error if `word` is undefined. – William Pursell Aug 02 '20 at 02:18
  • @WilliamPursell thx ('what' was missing from my question) – Erwann Aug 02 '20 at 03:44
  • 2
    What is the `-e` argument passed here in shebang? – Yatharth7 Oct 14 '20 at 08:34
  • @Yatharth7 Checked in the `man bash`: *"Subshells spawned to execute command substitutions inherit the value of the -e option from the parent shell."* – Neinstein Aug 18 '22 at 07:51
121
[ -s file.name ] || echo "file is empty"
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
mickey white
  • 1,219
  • 1
  • 8
  • 2
  • 20
    [[ -s file.name ]] && echo "full" || echo "empty" – McPeppr Jan 29 '18 at 20:27
  • 1
    `[[ -s file.name ]] || { [[ -f file.name ]] && echo 'empty' || echo 'does not exist'; }` – smarber Apr 11 '18 at 10:42
  • 3
    @smarber for simple check like this, please use `[ ... ]` instead of `[[ ... ]]`. The latter is bashism, which should be used only for incompatible bash checks (e.g. regexp). If you ever happen to write anything which should be POSIX shell portable (e.g. Debian system scripts), you'll appreciate this habit yourself :). – pevik May 19 '21 at 10:00
77

[ -s file ] # Checks if file has size greater than 0

[ -s diff.txt ] && echo "file has something" || echo "file is empty"

If needed, this checks all the *.txt files in the current directory; and reports all the empty file:

for file in *.txt; do if [ ! -s $file ]; then echo $file; fi; done
pevik
  • 4,523
  • 3
  • 33
  • 44
Surya
  • 11,002
  • 4
  • 57
  • 39
  • 4
    You don't need to do `$(ls *.txt`, and in fact shouldn't. Some people have defaults set for `ls` that use the long format (like me) and the shell will already expand `*.txt` on its own. Just do `for file in *.txt` instead. – PrincessRTFM Jun 26 '18 at 17:19
  • Nice! If you'd like to check all txt files recursively, you can use `find` like this: `for file in $(find . -name '*.txt'); do if [[ ! -s $file ]]; then echo $file; fi; done` – KlimczakM Nov 08 '18 at 07:28
24

To check if file is empty or has only white spaces, you can use grep:

if [[ -z $(grep '[^[:space:]]' $filename) ]] ; then
  echo "Empty file" 
  ...
fi
Noam Manos
  • 15,216
  • 3
  • 86
  • 85
  • 6
    This is the only good answer and should be the accepted one. Using `-s` does not answer the question. It looks for a file that does exist and has a size of more than 0 bytes. – Akito May 21 '20 at 11:36
19

While the other answers are correct, using the "-s" option will also show the file is empty even if the file does not exist.
By adding this additional check "-f" to see if the file exists first, we ensure the result is correct.

if [ -f diff.txt ]
then
  if [ -s diff.txt ]
  then
    rm -f empty.txt
    touch full.txt
  else
    rm -f full.txt
    touch empty.txt
  fi
else
  echo "File diff.txt does not exist"
fi
geedoubleya
  • 488
  • 6
  • 12
17

Easiest way for checking if file is empty or not:

if [ -s /path-to-file/filename.txt ]
then
     echo "File is not empty"
else
     echo "File is empty"
fi

You can also write it on single line:

[ -s /path-to-file/filename.txt ] && echo "File is not empty" || echo "File is empty"
Nabeel Shaikh
  • 1,198
  • 1
  • 14
  • 27
10

@geedoubleya answer is my favorite.

However, I do prefer this

if [[ -f diff.txt && -s diff.txt ]]
then
  rm -f empty.txt
  touch full.txt
elif [[ -f diff.txt && ! -s diff.txt ]]
then
  rm -f full.txt
  touch empty.txt
else
  echo "File diff.txt does not exist"
fi
smarber
  • 4,829
  • 7
  • 37
  • 78
7
[[ -f filename && ! -s filename ]] && echo "filename exists and is empty"
Radek 'Goblin' Pieczonka
  • 21,554
  • 7
  • 52
  • 48
3

Many of the answers are correct but I feel like they could be more complete / simplistic etc. for example :

Example 1 : Basic if statement

# BASH4+ example on Linux :

typeset read_file="/tmp/some-file.txt"
if [ ! -s "${read_file}" ]  || [ ! -f "${read_file}" ] ;then
    echo "Error: file (${read_file}) not found.. "
    exit 7
fi

if $read_file is empty or not there stop the show with exit. More than once I have had misread the top answer here to mean the opposite.

Example 2 : As a function

# -- Check if file is missing /or empty --
# Globals: None
# Arguments: file name
# Returns: Bool
# --
is_file_empty_or_missing() {
    [[ ! -f "${1}" || ! -s "${1}" ]] && return 0 || return 1
}
Mike Q
  • 6,716
  • 5
  • 55
  • 62
1

Similar to @noam-manos's grep-based answer, I solved this using cat. For me, -s wasn't working because my "empty" file had >0 bytes.

if [[ ! -z $(cat diff.txt) ]] ; then
    echo "diff.txt is not empty"
else
    echo "diff.txt is empty"
fi
J. Tylka
  • 161
  • 1
  • 6
  • The test value is unquoted. Won’t this get into big problems, if diff.txt contains e.g. ` 'x' ]] && rm -rf /home; # `? – Evi1M4chine Jan 01 '23 at 17:39
0

I came here looking for how to delete empty __init__.py files as they are implicit in Python 3.3+ and ended up using:

find -depth '(' -type f  -name __init__.py ')' -print0 |
  while IFS= read -d '' -r file; do if [[ ! -s $file ]]; then rm $file; fi; done

Also (at least in zsh) using $path as the variable also breaks your $PATH env and so it'll break your open shell. Anyway, thought I'd share!

SamMorrowDrums
  • 552
  • 5
  • 15
0
  1. (For the guys above) I'm not sure if you really want to use logical operators inside the [[ program. Probably you should use [[ expr_1 ]] && [[ expr_2 ]] instead of [[ expr_1 && expr_2 ]].
  2. The expression [[ -s file.txt ]] also checks if the file exists, so I don't see any reason to use -f before that.

This a simple statement to check if a file exists, is not empty and contains 0:

if [[ ! -s ./example.txt  ]] || grep -q 0 "./example.txt"; then
  echo "example.txt doesn't exist, is empty or contains 0"
else
  echo "example.txt contains 1"

Last note: Mind that empty file isn't always empty:

  • touch example.txt - this file is empty
  • echo "" > example.txt - this file is NOT empty
Andreas
  • 41
  • 5