-1

I have a script which installs a tool, if it's not already on my system:

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [ -x $ASCIIDOCTOR_BIN ]; then  ......

The problem is, that it doesn't seem to be working: the conditional expression always evaluates to false.

Even with

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [ false ]; then  ......

the condition turns out to be just false.

As I was playing around with it I found out that if I replace the brackets with double brackets, it works:

#!/bin/bash
ASCIIDOCTOR_BIN=`command -v asciidoctor`
if ! [[ -x $ASCIIDOCTOR_BIN ]]; then  ......

Can any1 explain why is that? I was told to avoid double brackets and curious, if there are other ways to make this script work.

I am working on Ubuntu 20.04.

ForestG
  • 17,538
  • 14
  • 52
  • 86
  • 1
    just out of curiosity, why were you told to avoid double brackets ? Their only downside is that they are not always portable, but if bash is the only shell you want to target [they are more robust](https://stackoverflow.com/questions/669452/is-double-square-brackets-preferable-over-single-square-brackets-in-ba) – Aserre Jan 20 '21 at 09:31
  • The first should print an *unary operator expected* error. Yet there is no mention of it in the question – oguz ismail Jan 20 '21 at 09:32
  • @Aserre https://stackoverflow.com/questions/669452/is-double-square-brackets-preferable-over-single-square-brackets-in-ba I asw this thread. – ForestG Jan 20 '21 at 09:34
  • @oguzismail it won't print that, not sure why is that tho... – ForestG Jan 20 '21 at 09:35
  • Can somebody please explain the downvotes? I try to improve the question if that's the case. – ForestG Jan 20 '21 at 09:54

1 Answers1

1

You problem is that you are missing quotes, and don't understand how parameter expansion works:

Consider the following, assuming you enter a bash prompt:

$ a=""
$ b="helloWorld"
$ bash -c 'for arg; do echo "got arg: $arg"; done' _ $a $b
got arg: helloWorld

You would assume that bash is called with the positional parameters:

$0 = _
$1 = "" # empty string
$2 = "helloWorld"

But in reality the parameter $a expands to nothing resulting in bash being called with:

$0 = _
$1 = "helloWorld"

Applying our knowledge to your example you will notice that if $ASCIIDOCTOR_BIN is empty, which it is when the command doesn't exists, the if statement will become:

if [ -x ]; then ...

Which will test if the string -x is empty, which it clearly isn't.

The solution to this is to always quote parameter expansions:

$ a=""
$ b="helloWorld"
$ bash -c 'for arg; do echo "got arg: $arg"; done' _ "$a" "$b"
got arg: 
got arg: helloWorld

One thing you should know about [ is that it isn't part of the language syntax but rather a command, usually implemented in the shell.

Same goes for true and false, these are also command, which means [ false ] is simply testing if the string false is empty, which it clearly isn't.

So parameter expansion etc applies to all it's arguments.

A note on [[. [[ is a special bash syntax where in parameter expansion works differently, and therefore you code works.

You can find a nice writeup on how parameter expansion works in bash: https://mywiki.wooledge.org/BashGuide/Parameters

Andreas Louv
  • 46,145
  • 13
  • 104
  • 123