Roland
Roland

Reputation: 7853

Bash if statement: Comparison not working with assignment

In the following test_if2() works as expected but test_if not. The difference is that in test_if() I do a variable assignment. Where is the error?

test_if() {
  declare file_path
  if [[ -n ${file_path=$(echo "")} || -n ${file_path=$(echo "Hi")} ]]; then
    echo Non null: ${file_path}
  else
    echo null
  fi      
}

test_if2() {
  declare file_path
  declare greet="Hello"
  if [[ -n $(echo "") || -n $(echo "Hi") ]]; then
    echo Non null
  else
    echo null
  fi      
}

test_if #prints null
test_if2 #prints Non null

Upvotes: 0

Views: 132

Answers (2)

Mark
Mark

Reputation: 4455

Use := instead of = for the behavior you are looking for.

${param=word} does not make the assignment if param is set but empty (which is what declare param does). Use ${param:=word} to cover the case of an empty param as well.

Your issue is that the assignment is not being performed and the returned value is empty.

I tested your expression on MacOS as follows:

file_path=Bye
echo ${file_path=$(echo "Hi")}  # returns Bye 
echo $file_path                 # returns Bye

And alternatively:

unset file_path
echo ${file_path=$(echo "Hi")}  # returns Hi 
echo $file_path                 # returns Hi

Lastly let's see if there is a different behavior when consider unset and empty:

file_path=""
echo ${file_path=$(echo "Hi")}  # returns nothing 
echo $file_path                 # returns nothing

And we may as well repeat your code exactly:

declare file_path
echo ${file_path=$(echo "Hi")}  # returns Nothing
echo $file_path                 # returns Nothing

So, if we review your code, we can see why test_if() return "null".

Thus, I'm going to conclude that ${param=word} makes the assignment only if param is unset. Consider this code instead:

test_if() {
  declare file_path
  if [[ -n ${file_path:=$(echo "")} || -n ${file_path:=$(echo "Hi")} ]]; then
    echo Non null: ${file_path}
  else
    echo null
  fi      
}

echo "test_if() returns $(test_if)" # test_if() returns Non null: Hi

The use of := assigns a value if the param is empty or unset. So, this will make your code work , since you declare file_path but didn't assign a value initially, leaving it empty (but set).

Upvotes: 1

Ted Lyngmo
Ted Lyngmo

Reputation: 117308

file_path="foo"

if [[ -n ${file_path=bar} ]]; then
    echo "got>$file_path<"
else
    echo "no file_path"
fi

The assignment of file_path inside the parameter expansion has no effect if file_path has already been set and the program will therefore print

got>foo<

The same happens in your condition.

The first condition sets file_path="" and since the -n test fails for blank strings, it tries the second condition.

The second will however not set file_path="HI" because it's already set to "" - and the second -n test therefore also fails.

Upvotes: 1

Related Questions