0

I'm new to bash so assume that I don't understand everything in this simple script as I've been putting this together as of today with no prior experience with bash.

I get this error when I run test.sh:

command substitution: line 29: syntax error near unexpected token `$1,'
./f.sh: command substitution: line 29: `index_of($1, $urls))'

FILE: f.sh

#!/bin/bash

urls=(    "example.com"   "example2.com")

error_exit()
{
    echo "$1" 1>&2
    exit 1
}

index_of(){
  needle=$1
  haystack=$2

  for i in "${!haystack[@]}"; do
    if [[ "${haystack[$i]}" = "${needle}" ]]; then
      echo "${i}"
    fi
  done

  echo -1
}

validate_url_param(){
  index=-2 #-2 as flag

  if [ $# -eq 0 ]; then
    error_exit "No url provided. Exiting"
  else
    index=$(index_of($1, $urls)) #ERROR POINTS TO THIS LINE
    if [ $index -eq -1 ]; then
      error_exit "Provided url not found in list. Exiting"
    fi
  fi

  echo $index
}

FILE: test.sh

#!/bin/bash

. ./f.sh

index=$(validate_url_param "example.com")

echo $index

echo "${urls[0]}"

I've lost track of all of the tweaks I tried but google is failing me and I'm sure this is some basic stuff so... thanks in advance.

5
  • 4
    The syntax for running a shell function is the same as a regular command -- there are no parentheses around the arguments (or commas between them). So, use index=$(index_of "$1" "$urls"). Correction: I just noticed that urls is an array, and you can't pass arrays as arguments. You could pass its name and use indirection, or pass its elements (each as a separate argument) and then convert those args back to an array in the function (or just iterate over the arguments directly). Commented Nov 13, 2019 at 8:25
  • 1
    What Gordon said. Also, it's valuable to run your scripts through shellcheck.net, It's often a much more detailed guide as to what's wrong than the errors you get from the interpreter. Commented Nov 13, 2019 at 8:28
  • Ah... thanks. I'll see if that works tomorrow. Commented Nov 13, 2019 at 8:32
  • And you'll want to avoid the useless echo. There is no need to capture standard output into a variable whose only purpose is that you echo it to standard output. Commented Nov 13, 2019 at 9:38
  • @tripleee if you are referring to my test.sh file, that is just a proof of concept and a learning tool. Commented Nov 13, 2019 at 18:03

1 Answer 1

1

The immediate error, just like the error message tells you, is that shell functions (just like shell scripts) do not require or accept commas between their arguments or parentheses around the argument list. But there are several changes you could make to improve this code.

Here's a refactored version, with inlined comments.

#!/bin/bash

urls=("example.com"   "example2.com")

error_exit()
{
    # Include script name in error message; echo all parameters
    echo "$0: $@" 1>&2
    exit 1
}

# A function can't really accept an array. But it's easy to fix:
# make the first argument the needle, and the rest, the haystack.
# Also, mark variables as local
index_of(){
  local needle=$1
  shift

  local i
  for ((i=1; i<=$#; ++i)); do
    if [[ "${!i}" = "${needle}" ]]; then
      echo "${i}"
      # Return when you found it
      return 0
    fi
  done
  # Don't echo anything on failure; just return false
  return 1
}

validate_url_param(){
  # global ${urls[@]} is still a bit of a wart
  if [ $# -eq 0 ]; then
    error_exit "No url provided. Exiting"
  else
    if ! index_of "$1" "${urls[@]}"; then
      error_exit "Provided url not found in list. Exiting"
    fi
  fi
}


# Just run the function from within the script itself
validate_url_param "example.com"
echo "${urls[0]}"

Notice how the validate_url_param function doesn't capture the output from the function it is calling. index_of simply prints the result to standard output and that's fine, just let that happen and don't intervene. The exit code tells us whether it succeeded or not.

However, reading the URLs into memory is often not useful or necessary. Perhaps you are simply looking for

grep -Fx example.com urls.txt
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the suggestions, the reason for the functions file is that they are to be used by a few scripts. This is why I do not call the function from within that file. Lots of good notes though. The reason for the array of domains is that I also have a parallel array of git branches that will use the same indexes.
I made a few slight changes but this was very helpful. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.