Bash Double Bracket Issue

bash double bracket issue

The problem lies in your script invocation. You're issuing:

$ sudo sh if_test.sh

On Ubuntu systems, /bin/sh is dash, not bash, and dash does not support the double bracket keyword (or didn't at the time of this posting, I haven't double-checked). You can solve your problem by explicitly invoking bash instead:

$ sudo bash if_test.sh

Alternatively, you can make your script executable and rely on the shebang line:

$ chmod +x if_test.sh
$ sudo ./if_test.sh

Also note that, when used between double square brackets, == is a pattern matching operator, not the equality operator. If you want to test for equality, you can either use -eq:

if [[ "14" -eq "14" ]]; then 
echo "FOO"
fi

Or double parentheses:

if (( 14 == 14 )); then 
echo "FOO"
fi

Are double square brackets [[ ]] preferable over single square brackets [ ] in Bash?

[[ has fewer surprises and is generally safer to use. But it is not portable - POSIX doesn't specify what it does and only some shells support it (beside bash, I heard ksh supports it too). For example, you can do

[[ -e $b ]]

to test whether a file exists. But with [, you have to quote $b, because it splits the argument and expands things like "a*" (where [[ takes it literally). That has also to do with how [ can be an external program and receives its argument just normally like every other program (although it can also be a builtin, but then it still has not this special handling).

[[ also has some other nice features, like regular expression matching with =~ along with operators like they are known in C-like languages. Here is a good page about it: What is the difference between test, [ and [[ ? and Bash Tests

An issue with double brackets in shell scripting

It sounds like your shell is POSIX sh, which does not have the [[ builtin. Possible solutions include translating it to an expression that works for sh or changing the shebang line to be #!/bin/bash. Changing the shebang is generally the best solution.

You may have a POSIX sh if you're on Ubuntu, they use dash.

How to use double or single brackets, parentheses, curly braces

In Bash, test and [ are shell builtins.

The double bracket, which is a shell keyword, enables additional functionality. For example, you can use && and || instead of -a and -o and there's a regular expression matching operator =~.

Also, in a simple test, double square brackets seem to evaluate quite a lot quicker than single ones.

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done

real 0m24.548s
user 0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done

real 0m33.478s
user 0m33.478s
sys 0m0.000s

The braces, in addition to delimiting a variable name are used for parameter expansion so you can do things like:

  • Truncate the contents of a variable

    $ var="abcde"; echo ${var%d*}
    abc
  • Make substitutions similar to sed

    $ var="abcde"; echo ${var/de/12}
    abc12
  • Use a default value

    $ default="hello"; unset var; echo ${var:-$default}
    hello
  • and several more

Also, brace expansions create lists of strings which are typically iterated over in loops:

$ echo f{oo,ee,a}d
food feed fad

$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")

$ for num in {000..2}; do echo "$num"; done
000
001
002

$ echo {00..8..2}
00 02 04 06 08

$ echo {D..T..4}
D H L P T

Note that the leading zero and increment features weren't available before Bash 4.

Thanks to gboffi for reminding me about brace expansions.

Double parentheses are used for arithmetic operations:

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

and they enable you to omit the dollar signs on integer and array variables and include spaces around operators for readability.

Single brackets are also used for array indices:

array[4]="hello"

element=${array[index]}

Curly brace are required for (most/all?) array references on the right hand side.

ephemient's comment reminded me that parentheses are also used for subshells. And that they are used to create arrays.

array=(1 2 3)
echo ${array[1]}
2

Bash - when using Double Square brackets and when single square brackets

Unlike [[ ]], single square brackets are subject to word splitting like normal commands. Think of it similarly as passing arguments to test builtin. [[ ]] are special and variables within it are not split with IFS. This is why it's preferable to use [[ ]] since it's more efficient and safer.

This one is just one of the things you can't do with [. With [ you'd play around with { } and ( ) to make it work. Note that ( ) summons a subshell and { } would always need a semicolon in the end which is ugly. However you can do it safely with [[ ]]:

[[ a != b && c != d && ( something || something ) ]]

By the way to fix your problem you have to place the variable in double-quotes to prevent splitting:

[ "$STRING" = dog ]

With [[ it's not needed.

Sere Word Splitting: https://www.gnu.org/software/bash/manual/html_node/Word-Splitting.html

Add:

It seems like $STRING there was actually skipped as an argument for being empty instead of being split. Similarly the concept of it being interpreted as a normal command would apply and applying double quotes would fix it.

Double-bracket if-statement not working

They both "work" for me, however you are using the wrong type of test. The > inside [[ is doing a textual comparison. For an arithmetic comparison either use the old -gt or (better) the correct brackets - double parentheses:

if (( nb_dd > 0 )); then
INPUT_TYPE="txt"
fi

Note that the $ is not used, since only numerics can be compared inside ((...)) (using a $ inside might work but can give strange side-effects because of expansion order).

double brackets add -n when use eval

[[ implicitly disables string-splitting, such that an expansion isn't split into multiple arguments.

A single-item test implicitly runs -n, testing whether that item is the empty string.

Thus, if you want pieces of your condition to be evaluated as separate arguments to [[, you should have the [[ within the eval, such that the condition is replaced with the text it contains before [['s parsing rules are in effect.

eval "[[ $myCondition ]]"

Thus, this would make your code:

myCondition='${queueName} == ${pattern}'
pattern="COMPLETELY_DIFFERENT_PATTERN"
queueName="QM.GCS.SRC.TOTO"
set -x ; eval "[[ $myCondition ]]" && echo CORRECT; set +x

...which emits on stderr the expected log:

+ eval '[[ ${queueName} == ${pattern} ]]'
++ [[ QM.GCS.SRC.TOTO == COMPLETELY_DIFFERENT_PATTERN ]]
+ set +x

Bash double square brackets regex match issue

Assuming you are running Bash 3.2 or newer, the bash manual (scroll down to the description of [[…]]) states:

Any part of the pattern may be quoted to force the quoted portion to be matched as a string.

And further:

If the pattern is stored in a shell variable, quoting the variable expansion forces the entire pattern to be matched as a string.

Before Bash 3.2, the example you provided would have worked as you expected.

Does not work to execute command in double brackets in bash

The short answer is:

  • [ and [[ expect an expression.

  • if expects a command.

Saying:

[[ $(command) ]]

would essentially execute:

[[ -n <command_output> ]]

which may or may not be what you want. On the other hand, saying:

$command && echo something || echo other

would echo something or other based on the return code of the command (0 and non-zero respectively).

How does Bash deal with brackets inside of double quoting?

Each command substitution establishes a new quoting context, so the correct way to avoid word splitting inside nested command substitutions is to use double quotes.

In this example, white space is preserved:

$ echo "$(echo "$(echo 'foo     bar')")" # outer echo sees 'foo     bar'
foo bar

However, missing any of the double quotes means that the string is split by the shell:

$ echo $(echo "$(echo 'foo     bar')") # outer echo sees 'foo' 'bar'
foo bar
$ echo "$(echo $(echo 'foo bar'))" # middle echo sees 'foo' 'bar'
foo bar

echo outputs each argument, separated by a spaces, which is where the single space between "foo" and "bar" comes from.



Related Topics



Leave a reply



Submit