Thursday, October 27, 2022

[SOLVED] Bash Shell Check passes script but at runtime syntax error: operand expected

Issue

I have the following bash script:

#!/bin/bash

# login x times and calculate avg login time, take note of slowest time and # of logins > 1s

function login() {

  startTime=$(date +%s)
  curl --location --request GET 'http://www.example.com'
  endTime=$(date +%s)

  local callDuration=$(expr $endTime - $startTime)
  echo "$callDuration"

}

numLogins=5
allCallDurations=()

echo "starting logins"
for i in $(seq $numLogins)
do

  modu=$(expr $i % 20)
  if [ $modu -eq "0" ]; then
    echo "20 more calls were made"
  fi

  duration=$(login)
  allCallDurations+=($duration)

done

avgDuration=$(expr $allCallDuration / $numLogins)

slowest=${allCallDurations[0]}
numSlowLogins=0
for i in $(seq $numLogins)
do

  if (( slowest > ${allCallDurations[$i]} )); then
    slowest=${allCallDurations[$i]}
  fi

  if (( ${allCallDurations[$i]} > 1 )); then
    numSlowLogins=$(expr $numSlowLogins + 1)
  fi

done

echo "finished:"
echo "average call duration (s): $avgDuration"
echo "slowest call (s):          $slowest"
echo "# calls > 1 second:        $numSlowLogins"

The idea is it uses curl to make n number of HTTP calls to a website (here I use example.com but in reality I'm making RESTful calls to my web service's login URL). It calculates the average call duration, the slowest call and the number of calls that took more than a second to return.

When I run this script through Shell Check it says everything is fine.

But when I run bash myscript.sh (that's the name of this script on my Mac OS file system), I get:

bash myscript.sh
starting logins
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   704  100    68   3171    306 --:--:-- --:--:-- --:--:--  3477
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   704  100    68   3142    303 --:--:-- --:--:-- --:--:--  3446
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   704  100    68   3214    310 --:--:-- --:--:-- --:--:--  3509
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   704  100    68   3142    303 --:--:-- --:--:-- --:--:--  3446
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   704  100    68   3320    320 --:--:-- --:--:-- --:--:--  3641
expr: syntax error
myscript.sh: line 45: {"json":"coming-back-from-server"}0")
myscript.sh: line 49: {"json":"coming-back-from-server"}0 > 1 ")
myscript.sh: line 45: {"json":"coming-back-from-server"}0")
myscript.sh: line 49: {"json":"coming-back-from-server"}1 > 1 : syntax error: operand expected (error token is "{"json":"coming-back-from-server"}1 > 1 ")
myscript.sh: line 45: {"json":"coming-back-from-server"}0")
myscript.sh: line 49: {"json":"coming-back-from-server"}0 > 1 ")
myscript.sh: line 45: {"json":"coming-back-from-server"}0")
myscript.sh: line 49: {"json":"coming-back-from-server"}0 > 1 ")
myscript.sh: line 45: {"json":"coming-back-from-server"}0")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")
finished:
average call duration (s): 
slowest call (s):          {"json":"coming-back-from-server"}0
# calls > 1 second:        0

Where {"json":"coming-back-from-server"} is just a placeholder for the actual json coming back from each curl execution, however its important to note that it is in fact printing JSON values for all of these.

Can anyone spot where I'm going awry, and why its failing whereas Shell Check says its good (I mean SC has a few warnings but no errors)?


Solution

As Charles Duffy has pointed out, shellcheck cannot diagnose runtime errors/issues.

In this case the allCallDurations[] array appears to be empty and this ties back to a typo in the program, consider the following spellings:

allCallDurations=()                # array name ends in 's'

allCallDuration+=(duration)        # missing 's' on end of array name

${allCallDurations[x]}             # array name ends in 's'; multiple references

You're actually building a different array (allCallDuration - no trailing s) from what is referenced in the rest of the code (allCallDurations - trailing s).

So, fix the one typo and then see what happens:

# replace:

allCallDuration+=(duration) 

# with:

allCallDurations+=(duration)    
               ^-----

NOTE: I wouldn't expect shellcheck to flag this issue since, technically, you are allowed to have 2 arrays with differeing names, even if the difference is a single trailing s

OK, so I can guess what the next couple issues may be ...

What's the difference in the following:

allCallDurations+=(duration)          # previously suggested edit

allCallDurations+=($duration)         # additional edit?

What do you think a call to login() should be returning? What happens if you call login() from the command prompt, ie, does it return what you're expecting?



Answered By - markp-fuso
Answer Checked By - Willingham (WPSolving Volunteer)