Home > Enterprise >  Bash Shell Check passes script but at runtime syntax error: operand expected
Bash Shell Check passes script but at runtime syntax error: operand expected

Time:10-20

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)
  allCallDuration =(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:

expr: not a decimal number: 'duration'
myscript.sh: line 45: slowest >  : syntax error: operand expected (error token is " ")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")
myscript.sh: line 45: slowest >  : syntax error: operand expected (error token is " ")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")
myscript.sh: line 45: slowest >  : syntax error: operand expected (error token is " ")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")
myscript.sh: line 45: slowest >  : syntax error: operand expected (error token is " ")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")
myscript.sh: line 45: slowest >  : syntax error: operand expected (error token is " ")
myscript.sh: line 49: > 1 : syntax error: operand expected (error token is "> 1 ")

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

CodePudding user response:

In

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

...nothing is invalid syntax until we know at runtime that ${allCallDurations[$i]} expands to " " instead of a number. It can't be detected by static checking.


Beyond that: expr should not be used in modern code. Use $(( )) for integer arithmetic, or bc for floating-point arithmetic.

CodePudding user response:

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 issue may be ... what's the difference in the following:

allCallDurations =(duration)          # previously suggested edit

allCallDurations =($duration)         # additional edit?
  • Related