9

I frequently run a simple bash command:

rpm -Uvh --define "_transaction_color 3" myPackage.rpm

which works properly.

But now I'm trying to script it into a bash file, and make it more flexible:

#!/bin/bash
INSTALL_CMD=rpm
INSTALL_OPT="-Uvh --define '_transaction_color 3'"

${INSTALL_CMD} ${INSTALL_OPT} myPackage.rpm

However, this keeps generating the error:

error: Macro % has illegal name (%define)

The error is coming from how --define and the quoted _transaction_color is handled.
I've tried a variety of escaping, different phrasing, even making INSTALL_OPT an array, handled with ${INSTALL_OPT[@]}.

So far, my attempts have not worked.
Clearly, what I want is extremely simple. I'm just not sure how to accomplish it.

How can I get bash to handle my --define argument properly?

3
  • You have tried INSTALL_OPT='-Uvh --define _transaction_color 3', right? Commented Nov 13, 2012 at 17:27
  • @sampson-chen: Tried that. "error: Macro %_transaction_color has empty body". Commented Nov 13, 2012 at 17:36
  • 1
    This is because bash reads your arguments as -Uvh and --define and '_transaction_color and 3'. You must use an array in this case (as shown below in Barmar's answer): INSTALL_OPT=(-Uvh --define '_transaction_color 3'). Then ${INSTALL_CMD} "${INSTALL_OPT[$@]}" myPackage.rpm works (with double quotes, as he mentionned). Commented Nov 13, 2012 at 18:00

2 Answers 2

15

The problem is that quotes are not processed after variable substitution. So it looks like you're trying to define a macro named '_transaction_color.

Try using an array:

INSTALL_OPT=(-Uvh --define '_transaction_color 3')

then:

"$INSTALL_CMD" "${INSTALL_OPT[@]}" myPackage.rpm

It's important to put ${INSTALL_OPT[@]} inside double quotes to get the requoting.

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

8 Comments

I will only +1 if you edit your post and remove the evil thing. It's terrible! Just leave the one with the array, as it is the only good practice!
Eval is evil if you're using untrusted user input. If you're using it with your own data, it's not so bad.
+1 for the array answer -- it's the only way to properly handle multiple words that may contain whitespace.
Yes, or echo "$CMD $OPT blahblah" | /bin/bash... Is this less evil than eval @gniourf_gniourf?
@Nate It performs re-quoting. This is explained in Arrays: If the word is double-quoted, ... ${name[@]} expands each element of name to a separate word.
|
-1

It might be a bash issue with word splitting on space:

Try:

#!/bin/bash

IFS=$'\n'

INSTALL_CMD=rpm
INSTALL_OPT='-Uvh'
INSTALL_OPT_DEFINE='--define _transaction_color 3'

${INSTALL_CMD} ${INSTALL_OPT} ${INSTALL_OPT_DEFINE} myPackage.rpm

5 Comments

I suspect --define requires the macro name and value to be in a single argument, so this won't work.
@Barmar Good point, I wasn't too sure about that part; updated my answer.
@sampson-chen: Tried setting IFS and breaking up the options as you describe. Result: "-Uvh: unknown option". (I don't understand why... but thats the error I got)
@abelenky: Try removing the quotes around INSTALL_OPT='-Uvh' (or using double-quotes). Also, I used backticks instead of single-quotes in my original answer by mistake, in case you copy and pasted anything.
I saw the back-ticks, and assumed you meant regular-ticks (but I tried it both ways to be sure). It looks like @Barmar's answer works; thanks for the effort.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.