0

I am trying to write a bash script that will take a single argument("prod" or "staging"), and use that to conditionally set global environment variables, specifically to switch between my staging and prod AWS keys. However, even though my logs in the script show what I expect, running echo $AWS_ACCESS_KEY in my terminal after running the script, does not show it was updated. I have tried adding source ~/.zshrc but I don't think that is needed. What can I change to update the $AWS_ACCESS_KEY globally?

#!/bin/bash

tmpAccess="access"
tmpSecret="secret"

if [ $1 == "prod" ];
then
    echo "Setting the AWS KEYS to $1 keys"
    tmpAccess=$PROD_ACCESS_KEY
    tmpSecret=$PROD_SECRET_KEY

elif [ $1 == "staging" ];
then
    echo "Setting the AWS KEYS to $1 keys"
    tmpAccess=$STAGING_ACCESS_KEY
    tmpSecret=$STAGING_SECRET_KEY
else
    echo "Unknown env passed in: $1"
fi

export AWS_ACCESS_KEY=$tmpAccess
export AWS_SECRETS_KEY=$tmpSecret
echo "Updated AWS_ACCESS_KEY: $AWS_ACCESS_KEY"
echo "Current tmpAccess: $tmpAccess"


echo "AWS_ACCESS_KEY has been updated to $AWS_ACCESS_KEY for env $1"
echo "AWS_SECRETS_KEY has been updated to $AWS_SECRETS_KEY for env $1"

source ~/.zshrc

My zshrc file looks similar to:

export STAGING_ACCESS_KEY=1234
export STAGING_SECRETS_KEY=abcd
export PROD_ACCESS_KEY=5678
export PROD_SECRETS_KEY=efgh
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
johnny_mac
  • 1,801
  • 3
  • 20
  • 48
  • 1
    Depending on your needs, using defined profiles in the ~/.aws/credentials file might provide an easier solution. See https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html – j_b Jan 18 '23 at 03:18
  • @j_b I appreciate the suggestion but lets assume I'm using the AWS keys as an example here, I still want to set global variables in a bash script – johnny_mac Jan 18 '23 at 03:20
  • 2
    You will not be able to affect the current environment from a child process (a script). To run a script that sets an environment variable, and have that change affect the current environment, you will need to source the script using either . (dot), or source in bash – j_b Jan 18 '23 at 03:26
  • 1
    There's no such thing as a global environment variable (at least in unix). See ["Setting environment variable in shell script does not make it visible to the shell"](https://stackoverflow.com/questions/8604462/setting-environment-variable-in-shell-script-does-not-make-it-visible-to-the-she). – Gordon Davisson Jan 18 '23 at 04:48
  • What is a _**global** environment variable_? You don't have variables defined inside functions, so talking of global vs. local does not make sense. – user1934428 Jan 18 '23 at 08:46
  • You are sourcing .zshrc (which defines `STAGING_ACCESS_KEY`) at the **end** of your script, but you are **using** this variable **before** that. Is this deliberate? BTW, when you run your script, it assumes that i.e. `PROD_ACCESS_KEY` is already defined, and since you don't set it anywhere, it means that the variable needs to be in the environment. This is a possible source for error. I suggest that you put a `set -u` at the start of the script, to catch such a case. – user1934428 Jan 18 '23 at 08:48
  • Use the bash tag for bash, the zsh tag for zsh, the sh tag for POSIX sh, and the `shell` tag for general UNIX shell questions. Never is the bash tag correct for questions about zsh. – Charles Duffy Jan 18 '23 at 20:51

1 Answers1

0

Clearly, it's not possible to put in a script a program to modify a variable in the current terminal except if you accept to source it (see Setting environment variable in shell script does not make it visible to the shell).

There is another solution. Put your script content in a function:

myfunctionName () {
    tmpAccess="access"
    tmpSecret="secret"

    if [ $1 == "prod" ];
    then
        echo "Setting the AWS KEYS to $1 keys"
        tmpAccess=$PROD_ACCESS_KEY
        tmpSecret=$PROD_SECRET_KEY

    elif [ $1 == "staging" ];
    then
        echo "Setting the AWS KEYS to $1 keys"
        tmpAccess=$STAGING_ACCESS_KEY
        tmpSecret=$STAGING_SECRET_KEY
    else
        echo "Unknown env passed in: $1"
    fi

    export AWS_ACCESS_KEY=$tmpAccess
    export AWS_SECRETS_KEY=$tmpSecret
    echo "Updated AWS_ACCESS_KEY: $AWS_ACCESS_KEY"
    echo "Current tmpAccess: $tmpAccess"

    echo "AWS_ACCESS_KEY has been updated to $AWS_ACCESS_KEY for env $1"
    echo "AWS_SECRETS_KEY has been updated to $AWS_SECRETS_KEY for env $1"
}

and put this function in your .zshrc file.

After that, launch a new terminal and call your myfunctionName function like the script filename.

Arnaud Valmary
  • 2,039
  • 9
  • 14
  • This is moot if the code is only going to be run with zsh, but for POSIX-y shells, `[ $1 == "prod" ]` should be `[ "$1" = prod ]`. Constant strings don't need to be quoted, but (on more POSIXy shells) variable expansions _do_ need to be quoted for consistent behavior, and `==` as a string comparison operator is a nonstandard extension only some versions of `test` support (see https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html). – Charles Duffy Jan 18 '23 at 20:49
  • Alternately, think about `case $1 in prod) ...;; staging) ...;; *) echo "Unknown env passed in: $1" >&2;; esac` (and do note the use of stderr for messages for the user -- that'll stop your dotfiles from breaking tools like scp that depend on stdout not being written to during the login process if this function is called automatically) – Charles Duffy Jan 18 '23 at 20:54
  • A pair of functions `set_prod_access` and `set_dev_access` would be much simpler than a single monolithic function that takes an argument. – chepner Jan 23 '23 at 14:35