0

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: ./myscript.sh dev01 tester

#!/bin/bash

set +x

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

# Setup VARS
CREDS="-x foobar -a ec2.local_ipv4"
ENVIRONMENT="$1"
ROLES="$2"

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

echo "Test 1"
deploy

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

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"

Again, Test 4 works only.

2
  • 2
    Consider making a habit of using deploy() { instead of function deploy { -- the former syntax works in any POSIX-compliant shell, whereas the latter depends on extensions and has no benefit to compensate for that lack of portability. And consider mklement0's note about all-uppercase variable names being in reserved space echoed. Commented Oct 29, 2016 at 4:03
  • 2
    ...back towards the topic of the immediate problem, btw, you might consider BashFAQ #50 additional reading (above and beyond the applicable, useful, and correct references given in said answer). Commented Oct 29, 2016 at 4:06

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome! Thanks for your clarity and detailed explanations! I appreciate the help.

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.