0

When I'm using one of the comparison operators/functions on an empty file, Bash returns that the file is not empty. There must be a newline character or something, but it's making all these tests pass when they shouldn't.

So is there another way to test if a file actually has a character? I've tried [ -s file.txt ], [ -n file.txt], and all its brethren, but they all return that the file.txt is not empty.

I've tried doing cat and assigning it to a variable, but that variable is read as not empty for some reason.

Any other way to see if a file is truly empty?

edit So here's what I've done. I cleared the file (ctrl+a and delete). Made sure when I tried moving cursor that the cursor doesn't move. Then I did if [ -n filename ] ; then echo "not empty"; fi; This returns not empty

6
  • 1
    Define "truly empty"? Does only spaces count as empty? Does only newlines count as empty? Does spaces and newlines count as empty? What about tabs? What about vertical tabs? What about other control characters? -s tells you if the file is entirely empty i.e. has no contents. If you need something else you'll need to figure out what you need and how to test for it. Commented Jun 18, 2015 at 17:32
  • Can you update the question to include the actual code you tried as well as the actual and expected output? For example, instead of saying "I've tried [ -s file.txt ]", can you say "I've tried this: > file.txt; ls -l file.txt; [ -s file.txt ] && echo "the file is empty" but it shows -rw-r------ 1 me me 0 Jun 18 10:32 file.txt while I expected it to also show "the file is empty" because the file size is 0"? Commented Jun 18, 2015 at 17:38
  • What does ctrl+a and delete mean? Which editor are you using? What does it save when you save that empty file? What does ls -l say is the size of the file? At this point, it sounds like it might be an editor problem, not a shell problem. Does your editor create empty files? Commented Jun 18, 2015 at 17:44
  • ctrl+a and delete to select everything and delete it. I'm using Notepad++ and ls -l shows 0 bytes, Windows also shows 0 bytes. I'm using Cygwin on windows Commented Jun 18, 2015 at 17:47
  • Mentioning Windows and Cygwin is helpful, though mostly Cygwin manages to run like Unix. Note that the -n operator is a string test, not a file test. What happens if you replace -n with -s? Commented Jun 18, 2015 at 17:48

1 Answer 1

1

The test for a non-empty file is:

[ -s file.txt ]

The test for an empty file, therefore, is:

[ ! -s file.txt ]

or you can use Bash's ! operator outside the test command:

if ! [ -s file.txt ]

Note that these operations consider a file 'empty' if it contains zero bytes. If it is bigger than that, it is not empty by definition. If you want to inspect the contents and ignore a file that contains only blanks and newlines, etc, then you need a different test altogether.

You can consider using the [[ command (a shell built-in with a number of special semantics) instead of [, though in this context, it makes no practical difference. The [[ command is not as portable as [.

Note that the -n option tests for a non-empty string (not a non-empty file).

[ -n file.txt ]

will always pass (because file.txt is not an empty string). It is used with variables:

[ -n "$variable" ]    # Is $variable non-empty
[ -z "$emptyvar" ]    # Is $emptyvar empty
Sign up to request clarification or add additional context in comments.

7 Comments

The part about "that variable is read as not empty for some reason." was probably due to using [ -n $variable ], which due to the lack of quoting is true for empty input.
@thatotherguy: If you have: variable="" followed by [ -n $variable ] then you have an erroneous invocation of the test built-in (at least, in classic shell -- meaning pre-POSIX 90; Bash seems to handle it, and so does Linux's /usr/bin/[). You could use [[ -n $variable ]] because that is special in many ways, whereas [ is just a regular command (there is usually a binary /bin/[ or /usr/bin/[ that you can use, though it is also a shell built-in).
No, it's not erronous; [ string ] is true when the string is not empty. Therefore, OP's var=$(cat emptyfile); [ -n $var ] would have expanded to [ -n ] which is true because "-n" is a non-empty string. Had the file contained "foo", it would have expanded to [ -n foo ] which is also true, this time because "foo" is non-empty.
POSIX may have changed things; it's entirely possible. I didn't bother to learn the sloppy techniques because the rigorous ones work reliably.
Could you be misremembering this? It was not changed in POSIX: it was this way in the original Bourne shell. This is because [ was an external utility (like GNU coreutils /usr/bin/[), and external utilities can not tell the difference between [ -n ] and [ -n $emptyvar ] due to argv being identical. You also can't error on [ -n ], because for the same reason you can't tell it apart from valid [ $1 ] when the first argument is -n.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.