While writing a bash script to help creating polaroid thumbnail using Imagick\'s convert
commmand. I encounter a problem. Although, I manage to work around with
CAPTION="$1"
IN_FILE="resources/puppy.png"
OUTFILE="resources/puppy_polaroid.png"
case "$CAPTION" in
"" ) CAPTION="-caption ''";;
* ) CAPTION='-caption "$CAPTION"';;
esac
convert $CAPTION "$IN_FILE" "$OUTFILE"
Putting backticks around $COMMAND
on the last line causes the script to try to execute the output of the command rather than the command itself.
$ c='echo hi'
$ `$c`
hi: command not found
This will work:
if [[ "$CAPTION" != "" ]]
then
convert -caption "$CAPTION" "$IN_FILE" "$OUTFILE"
else
convert "$IN_FILE" "$OUTFILE"
fi
You'll want to read entry 050 in the BASH FAQ:
I'm trying to put a command in a variable, but the complex cases always fail!
Variables hold data. Functions hold code. Don't put code inside variables! There are many situations in which people try to shove commands, or command arguments, into variables and then run them. Each case needs to be handled separately.
...
- I'm constructing a command based on information that is only known at run time
The root of the issue described above is that you need a way to maintain each argument as a separate word, even if that argument contains spaces. Quotes won't do it, but an array will. (We saw a bit of this in the previous section, where we constructed the addrs array on the fly.)
If you need to create a command dynamically, put each argument in a separate element of an array. A shell with arrays (like Bash) makes this much easier. POSIX sh has no arrays, so the closest you can come is to build up a list of elements in the positional parameters. Here's a POSIX sh version of the sendto function from the previous section:
Use an array, as so:
#!/bin/bash
# ^^^ - note the shebang line explicitly using bash, not /bin/sh
CAPTION="Is this Cute?" # The actual value will be tacked from the parameter of this bash.
IN_FILE="resources/puppy.png"
OUTFILE="resources/puppy_polaroid.png"
extra_args=( )
if [[ $CAPTION ]] ; then
extra_args+=( -caption "$1" )
fi
convert "${extra_args[@]}" "$INFILE" "$OUTFILE"
This construct presumes that you're potentially going to be appending numerous extra arguments. Note that +=
is unsupported in some older versions of bash which are still present on systems deployed in the field (most notably RHEL4). For such older releases it can be necessary to write extra_args=( "${extra_args[@]}" -caption "$1" )
to append to an array.