views:

39

answers:

3

I'm having trouble preserving whitespace in a bash script:

CURRENT_YEAR=$(date "+%Y")
MESSAGE=$(eval echo "$(/usr/libexec/PlistBuddy -c "Print NSHumanReadableCopyright" Info.plist)")

/usr/libexec/PlistBuddy -c "Set NSHumanReadableCopyright $MESSAGE" ${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}

The relevant section Info.plist:

<NSHumanReadableCopyright>Copyright © BEC, ${CURRENT_YEAR}\nAll rights reserved.</NSHumanReadableCopyright>

The script reads a value from a plist, then substitutes another variable (CURRENT_YEAR) into the the value that was read from the plist.

The problem is that the new line in MESSAGE is causing problems. If I use \n then an 'n' is displayed instead of a new line. If an actual new line character is used then the command fails because 'All' is interpreted as a new command.

How do I escape the new line? Is there a better way to do this? I have very little bash-foo.

Update - Solution:

Thanks for the help. The solution was to go crazy with quotes. Here's the finished result:

CURRENT_YEAR="$(date "+%Y")"
MESSAGE_TEMPLATE="$(/usr/libexec/PlistBuddy -c "Print NSHumanReadableCopyright" Info.plist)"
MESSAGE=$(eval echo '"'"$MESSAGE_TEMPLATE"'"')
/usr/libexec/PlistBuddy -c "Set NSHumanReadableCopyright $MESSAGE"  ${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}
+1  A: 

I don't see what PlistBuddy is doing well enough to know if this is the problem, but your code smells:

CURRENT_YEAR=$(date "+%Y")
MESSAGE=$(eval echo ...)

should be

CURRENT_YEAR="$(date "+%Y")"
MESSAGE="$(eval echo ...)"

(Note the extra doublequotes around $(...).)

With luck, this will fix the problem and you can just put unescaped newlines in your file, without getting All interpreted as a command. Otherwise it may be a PlistBuddy problem.

Norman Ramsey
A: 

Try adding this right after the MESSAGE=$(eval echo... line:

printf -v MESSAGE "%q" "$MESSAGE"

That will store the value of $MESSAGE back to itself with characters such as \ escaped.

Dennis Williamson
This escapes all the other meta characters too which prevents eval from substituting in $CURRENT_YEAR.
Benedict Cohen
+1  A: 

You have to get double-quotes around the string being eval'ed (so it'll substitute for the ${} expression, but not treat the newline as a separator between commands). This is kind of difficult, since there's no clean way to put a double-quote inside a double-quoted string; but you can do it by putting single-quoted double-quotes around the double-quoted string (oh, and then I always put double-quotes around the whole thing, even though I don't know that it's truly necessary):

CURRENT_YEAR=$(date "+%Y")
MESSAGE="$(eval echo '"'"$(/usr/libexec/PlistBuddy -c "Print NSHumanReadableCopyright" Info.plist)"'"')"

(If you're having trouble parsing that, '"' is a double-quote (protected by single-quotes to keep it from being evaluated until eval gets it), "$(...)" is the result of PlistBuddy (protected by double-quotes), and then '"' is another protected double-quote.

After that I think your PlistBuddy Set command will work ok, but I've had to quote its values before, so just in case:

/usr/libexec/PlistBuddy -c "Set NSHumanReadableCopyright '${MESSAGE//\'/\'}'" ${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}

(what that does is put single-quotes around $MESSAGE, after escaping any embedded single-quotes.)

Gordon Davisson