Does Not Work to Execute Command in Double Brackets in Bash

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).

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

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).

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.

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

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

run command inside of ${ curly braces

You can't run a command inside ${}, except in the fallback clause for when a value is not set (in POSIX sh or bash; might be feasible in zsh, which allows all manner of oddball syntax).

Regardless, far fewer contortions are needed if using a function:

# yes, you can call this cd, if you *really* want to.
cdr() {
if (( $# )); then
command cd "$@"
else
local home
home=$(git rev-parse --show-toplevel 2>/dev/null) || home=$HOME
command cd "$home"
fi
}

Note:

  • Using a function lets us test our argument list, use branching logic, have local variables, &c.
  • command cd is used to call through to the real cd implementation rather than recursing.

Double parenthesis with and without dollar

In the following, I use "returns" to indicate return values and "produces" to indicate "substitutes the resulting text."

  • $(...) means execute the command in the parens in a subshell and produces its stdout. Example:

      $ echo "The current date is $(date)"
    The current date is Mon Jul 6 14:27:59 PDT 2015
  • (...) means run the commands listed in the parens in a subshell. Example:

      $ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
    inside: a=2
    outside: a=1
  • $((...)) means perform arithmetic and produce the result of the calculation. Example:

      $ a=$((2+3)); echo "a=$a"
    a=5
  • ((...)) means perform arithmetic, possibly changing the values of shell variables, but don't produce its result. Example:

      $ ((a=2+3)); echo "a=$a"
    a=5

    Note that the return value of the calculation is returned, so it can be used in while or if.

  • ${...} means produce the value of the shell variable named in the braces. Example:

      $ echo ${SHELL}
    /bin/bash
  • {...} means execute the commands in the braces as a group. Example:

      $ false || { echo "We failed"; exit 1; }
    We failed

More generally what does the dollar sign stand for?

It means whatever it means in the given context.

What is the function of * between double brackets?

I'm going to assume you had backticks instead of single quotes for the command, and no space in !=:

[[ `/bin/somecommand 2>dev/null` != *'1'* ]]

In a double bracket [[ .. ]] expression, the right-hand side of =/== and != is interpreted as a glob pattern, so * means "any string".

Essentially, *'1'* will match all string that contains a 1 anywhere (such as foo1bar and 3210), while '1' will only match exactly the string 1.



Related Topics



Leave a reply



Submit