bashshellreturn-code

Strange behaviour with envsubst command


I try to check the command return inside my bash script for all commands. I created a function for this named check_command_return_code. This function is called in some other function which run command and it seems to work as expected except for the envsubst command.

This is my check_command_return_code:

check_command_return_code(){
  "$@"
  if [ "$?" -ne 0 ]; then
    echo "[ERROR] Error with command $@"
    exit 1
  fi
  echo "[SUCCESS] Command $@ has successfully run"
}

I also write this function in order to substitute env variable inside yaml file:

substitute_env_variables_into_file(){
  echo "Create new file named $2 from $1 by substituting environment variables within it"
  check_command_return_code envsubst < $1 > $2

}

I call my function which proceeds the substitution like this:

substitute_env_variables_into_file "./ingress-values.yaml" "./ingress-values-subst.yaml"

This is my ingress-values.yaml file:

controller:
  replicaCount: 2
  service:
    loadBalancerIP: "$INTERNAL_LOAD_BALANCER_IP"
    annotations:
      service.beta.kubernetes.io/azure-load-balancer-internal: "true" 

I expect my ingress-values-subst.yaml looks like this:

controller:
  replicaCount: 2
  service:
    loadBalancerIP: "my_private_ip"
    annotations:
      service.beta.kubernetes.io/azure-load-balancer-internal:

Unfortunately the ingress-values-subst.yaml is expanded with the echo of my check_command_return_code function as you can see:

controller:
  replicaCount: 2
  service:
    loadBalancerIP: "my_private_ip"
    annotations:
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"
[SUCCESS] Command envsubst has successfully run

I enabled the "debug" mode thanks to the following command in order to have more verbosity:

set -x

These logs are those from the output of my script:

++ substitute_env_variables_into_file ./private-ingress-values.yaml ./private-ingress-values-subst.yaml
++ echo 'Create new file named ./ingress/private-ingress-values-subst.yaml from ./private-ingress-values.yaml by substituting environment variables within it'
Create new file named ./private-ingress-values-subst.yaml from ./private-ingress-values.yaml by substituting environment variables within it
++ check_command_return_code envsubst
++ envsubst
++ '[' 0 -ne 0 ']'
++ echo '[SUCCESS] Command envsubst has successfully run'

I don't understand why the parameter of my command envsubst are not passed into my check_command_return_code function as you can see in the previous logs.

Thanks in advance for your help


Solution

  • I don't understand why the parameter of my command envsubst are not passed into my check_command_return_code

    Redirections are not parameters. Redirections are opened at the time the line is executed.

    When you do your_function > file, then inside your_function standard output is redirected to file for the whole duration of the function, including all the commands inside your_function.

    Wrap it in yet another function:

    myenvsubst() {
        envsubst < "$1" > "$2"
    }
    check_command_return_code myenvsubst "$1" "$2"
    

    Or better yet, write log information to standard error, or another file descriptor.

        echo "[ERROR] Error with command $*" >&2
    

    Check your scripts with shellcheck to find such problems like:

    < $1 > $2
    

    are not quoted. They should be < "$1" > "$2"

    if [ "$?" -ne 0 ]; then
    

    is an antipattern. Prefer if ! "$@"; then.

    echo "[ERROR] Error with command $@"
    

    is an odd usage of quoted $@. Prefer $*, or move to a separate argument.