0

In bash, I want to write a function that can output a log for the user, and return a string to set a variable (it's main purpose). The challenge I'm having is that usually a function must echo its output to return anything other than an exit code, but then that prevents logging other output within the function.

Is there a way to do this? The reason I ask is because other commands may output to stderr or stdout within the function, but I need to protect the variable from their output.

Here is some example code that wont work:

function retrieve_ami {
  local -r latest_ami="$1"
  local -r ami_role="$2"
  local -r ami_commit_hash="$3"
  local result=""
  if [[ "$latest_ami" == true ]]; then
    ami_filters="Name=tag:ami_role,Values=$ami_role"
    printf "\n...Query latest AMI"
  else
    ami_filters="Name=tag:ami_role,Values=$ami_role Name=tag:commit_hash,Values=$ami_commit_hash"
    printf "\n...Query AMI with commit: $ami_commit_hash"
  fi
  query=$(aws ec2 describe-images --filters $ami_filters --owners self --region $AWS_DEFAULT_REGION --query 'sort_by(Images, &CreationDate)[].ImageId' --output json | jq '.[-1]' --raw-output)
  if [[ "$query" != "null" ]]; then
    result="$query"
    printf "\nFound $ami_role result="
    printf "\n  $result\n"
  fi
  if [[ -z "$result" ]]; then
    printf "Images required for deployment are not present.  You will need to build them before continuing."
  fi
  # here we want to output the actual result #
  return $result
}
# And set the var
ami=$(retrieve_ami $latest_ami $ami_role $TF_VAR_ami_commit_hash)
openCivilisation
  • 796
  • 1
  • 8
  • 25

1 Answers1

1

The bash functions are more like a segment of additional commands invoked, they don't return a value. In addition to that, return is used to return an exit code, e.g. return 1.

You can set the return to 0 (if ami found) and pass the ami through a new variable, it can be that result (it can't be local any more). Try something like that instead (hopefully I haven't messed up, I can't test it at the moment):

#!/bin/bash

function retrieve_ami() {
  local -r latest_ami="$1"
  local -r ami_role="$2"
  local -r ami_commit_hash="$3"
  unset result
  if [[ "$latest_ami" == true ]]; then
    ami_filters="Name=tag:ami_role,Values=$ami_role"
    printf "\n...Query latest AMI"
  else
    ami_filters="Name=tag:ami_role,Values=$ami_role Name=tag:commit_hash,Values=$ami_commit_hash"
    printf "\n...Query AMI with commit: $ami_commit_hash"
  fi
  query=$(aws ec2 describe-images --filters $ami_filters --owners self --region $AWS_DEFAULT_REGION --query 'sort_by(Images, &CreationDate)[].ImageId' --output json | jq '.[-1]' --raw-output)
  if [[ "$query" != "null" ]]; then
    result="$query"
    printf "\nFound $ami_role result="
    printf "\n  $result\n"
    return 0
  fi
  if [[ -z "$result" ]]; then
    printf "Images required for deployment are not present.  You will need to build them before continuing."
    return 1
  fi
}
# And set the var
if retrieve_ami $latest_ami $ami_role $TF_VAR_ami_commit_hash; then
  # function returned true / 0
  ami=${result}
else
  # function returned an error / 1
  echo "Error finding ami"
fi

Just be careful not to use a variable already used before / not to overwrite it elsewhere

Please double check the following links for more information:

Oliniusz
  • 413
  • 3
  • 8