That's the key question when you're writing Bash scripts! Labby definitely recommends favoring [[ ]] in most modern Bash scripting due to its enhanced features and safety.
Here's a breakdown of when to prefer [[ ]] over [ ]:
Prefer [[ ]] (almost always) when:
- You are writing a script specifically for Bash (or compatible shells like Zsh, Ksh). If portability to strict POSIX
shis not a concern,[[ ]]is generally the better choice. - You need more advanced string comparisons:
- Pattern matching: For example, checking if a string starts with "hello" using
[[ "$var" == hello* ]]. This is much simpler than usinggreporcasewith[ ]. - Regular expression matching: Using the
=~operator, e.g.,[[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]].
- Pattern matching: For example, checking if a string starts with "hello" using
- You are combining multiple conditions with
&&or||:[[ "$VAR1" = "value1" && "$VAR2" -gt 10 ]]is much cleaner and more robust than chaining[ ](e.g.,[ "$VAR1" = "value1" ] && [ "$VAR2" -gt 10 ]).- Avoid the deprecated
-aand-ooperators that are sometimes used with[ ]for logical AND/OR.
- You want to avoid unexpected word splitting or pathname expansion:
[[ ]]treats unquoted variables more safely. For instance, ifMY_VARcontains spaces,[ "$MY_VAR" = "some value" ]is necessary, but[[ $MY_VAR = "some value" ]]often works correctly without quotingMY_VAR(though quoting is still a good habit). This helps prevent subtle bugs.
- You are checking for the existence of commands or external programs:
[[ -x "$(command -v some_command)" ]]allows you to check if a command exists and is executable in a robust way, ascommand -vmight output a path with spaces.
When you might still use [ ]:
- Strict POSIX shell scripting: If your script absolutely must run on any POSIX-compliant
sh(not just Bash), then you should stick to[ ]because[[ ]]is a Bash-specific extension. - External command evaluation: Sometimes you're evaluating the exit status of an actual external command rather than a shell built-in condition. For example,
if grep "pattern" file.txt; then ... fidirectly usesgrep's exit status.
General Recommendation:
For virtually all Bash scripts written today, prefer [[ ]]. It makes your code safer, more flexible, and often more readable. The only real exception is when strict POSIX compliance is a requirement.
You can see this in your string_logic.sh script, where [[ "$STRING1" != "$STRING2" ]] and [[ -z "$STRING3" ]] showcase its usage, helping to handle string comparisons cleanly.
Does that clarify the preferred usage between the two?