noober noober - 11 months ago 50
Bash Question

shell programming - how to properly pass variables within a function

What's wrong with my bash script? I'm trying to pass positional parameters within a function. My last test -

Test 4
works but its basically the command that I would run on the command line, no variable substitution.

I would like to call my function. Can someone tell me if the construction of my first 3 tests are valid and how to I can correct them? Thanks!

To execute:
./ dev01 tester


set +x

if [[ $# != 2 ]]; then
echo "Usage: ./ <ENV> <COMPONENT>"
exit 1

# Setup VARS
CREDS="-x foobar -a ec2.local_ipv4"

function deploy {
knife ssh "$CREDS" "chef_environment:"$ENVIRONMENT" AND roles:*"$ROLES"*" "uname"

echo "Test 1"

echo "Test 2"
DEPLOY=$(knife ssh "$CREDS" "chef_environment:"${ENVIRONMENT}" AND roles:*"${ROLES}"*" "uname")

echo "Test 3"
knife ssh "$CREDS" "chef_environment:"$ENVIRONMENT" AND roles:*"$ROLES"*" "uname"

echo "Test 4"
knife ssh -x foobar -a ec2.local_ipv4 "chef_environment:dev01 AND roles:*tester*" "uname"

Test 4
works only.

Answer Source

Your problem is unrelated to using a function; it has to do with how you're storing arguments in a variable and using that variable later:

If you want to store multiple arguments in a (non-array) variable, you cannot reference that variable double-quoted, because the value is then passed as a single argument to the target utility.

An immediate fix would be to use $CREDS unquoted, but that makes the value subject to potentially unwanted shell expansions, so the robust way to pass multiple arguments is to use an array:

# Store args. individually as array elements
CREDS=( '-x' 'foobar' '-a' 'ec2.local_ipv4' )

# ...

# "${CREDS[@]}" passes the elements of the array safely as *individual*
# arguments.
knife ssh "${CREDS[@]}" "chef_environment:$ENVIRONMENT AND roles:*$ROLES*" "uname"

Also note how I've embedded the $ENVIRONMENT and $ROLES variable references directly in the double-quoted string, which also makes the command more robust.

Finally, it's better not to use all-uppercase shell-variable names in order to avoid conflicts with environment variables and special shell variables.