Bash & Shell Scripting DISCUSSION

Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

Started by jiridekar Bash test commanddouble bracketsarithmetic comparisonunary operator expectedstring vs integer
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

jiridekar Bash & Shell Scripting Forum
#1

In a monitoring script I wrote if [ $count > 10 ]; then. The branch runs every time, whatever the count, and afterwards there is an empty file named 10 in the directory. A second test, if [ $mode == "auto" ], stops with unary operator expected when mode has not been set.

What is wrong with these, and what are the differences between single brackets, double brackets and double parentheses?

Community replies 5

Re: Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

#2

[ is an ordinary command (a builtin, identical to test), and its arguments are parsed like those of any other command. So > 10 is an output redirection: the shell creates the file 10, and the command that remains is [ $count ], which is true whenever the string is non-empty. For integers inside single brackets use the letter operators: -eq, -ne, -lt, -le, -gt, -ge. The correct test is [ "$count" -gt 10 ].

Re: Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

#3

The second error is a quoting problem. With mode empty, the unquoted $mode disappears completely and the command becomes [ == auto ], which is missing its left operand. Quote it, [ "$mode" = "auto" ], and an empty value is passed as an empty argument and simply compares unequal.

Inside single brackets the portable string-equality operator is a single =. Bash accepts == there too, but a strict POSIX sh may not.

Re: Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

#4

[[ ... ]] is Bash syntax rather than a command, so the shell parses it specially: variables are not word-split or glob-expanded, and < and > are comparison operators, not redirections. But they compare strings, so [[ 9 > 10 ]] is true because "9" sorts after "1". For numbers you still need -gt and friends inside double brackets.

What double brackets add is pattern and regex matching: [[ $file == *.log ]] tests against a glob pattern, and [[ $line =~ ^ERR([0-9]+) ]] matches a regular expression and leaves the captured digits in ${BASH_REMATCH[1]}.

Re: Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

#5

For arithmetic, (( ... )) reads most naturally: if (( count > 10 )); then. Inside it the usual C-style operators work, variables need no $, and the command succeeds when the result is non-zero. Bash arithmetic is integer only, so compare fractional values with a tool such as awk or bc.

Two traps: a number with a leading zero is read as octal, so (( 08 + 1 )) is an error; write (( 10#$n + 1 )) to force base 10 when parsing things like times and dates. And (( i++ )) returns a failure status when the old value of i was 0, which ends a script running under set -e.

Re: Bash if test is always true and creates a stray file: when to use [ ], [[ ]] or (( ))?

#6

A workable convention: (( )) for integer comparisons, [[ ]] for strings, patterns and file tests in scripts that declare #!/bin/bash, and quoted single brackets only when the script must run under plain sh.

File tests work in both bracket forms: -e exists, -f regular file, -d directory, -r readable, -s non-empty, and -z and -n for empty and non-empty strings. When a condition misbehaves, run the script with bash -x; the trace shows each test after expansion, which would have revealed [ == auto ] immediately.

TEP COMMUNITY