Search code examples
bashcygwin

bash shell script error works on command line, not in script


When running a shell script via Cygwin64, I am getting an error (output below). The relevant portion of the script follows. What is interesting is that if I copy and paste the echoed command, it runs without complaint. So, what is it I am failing to do properly?

[worldwidewilly@SAL9000 resources]$ makebook MyBook
Generating dblatex PDF output via a2x
a2x -v -f pdf -L --asciidoc-opts='-a lang=en -v -b docbook -d book' --dblatex-opts='-V -T db2latex' MyBook.asciidoc
Usage: a2x [OPTIONS] SOURCE_FILE

a2x: error: option -d: invalid choice: "book'" (choose from 'article', 'manpage',   'book')
done.

Here is the script logic:

ASCIIDOC_OPTS="--asciidoc-opts='-a lang=en -v -b docbook -d book'"
DBLATEX_OPTS="--dblatex-opts='-V -T db2latex'"
echo "Generating dblatex PDF output via a2x"
cmd="a2x -v -f pdf -L ${ASCIIDOC_OPTS} ${DBLATEX_OPTS} $1.asciidoc"
echo $cmd
$cmd
echo "done."

The script has been saved as UTF-8 with *nix file endings. This is a fresh install of Cygwin64 running on Windows 7.

FWIW - I have something of a workaround. If I add a space after the word book and before the single apostrophe, it gets by the error above. However, then the -T in the DBLATEX_OPTS is flagged as in error.

[worldwidewilly@SAL9000 resources]$ makebook MyBook
Generating dblatex PDF output via a2x
a2x -v -f pdf -L --asciidoc-opts='-a lang=en -v -b docbook -d book ' --dblatex-opts='-V -T db2latex' MyBook.asciidoc
Usage: a2x [OPTIONS] SOURCE_FILE
a2x: error: no such option: -T
done.

And, again, if I copy the echoed command and run it from the command line, it works. This is all very confusing.


Solution

  • Variables are supposed to contain data, and bash treats them as data. This means that shell meta-characters like quotes are also treated as data.

    See this article for a complete discussion on the topic.

    The short answer is to use arrays instead:

    ASCIIDOC_OPTS=( --asciidoc-opts='-a lang=en -v -b docbook -d book' )
    DBLATEX_OPTS=( --dblatex-opts='-V -T db2latex' )
    cmd=(a2x -v -f pdf -L "${ASCIIDOC_OPTS[@]}" "${DBLATEX_OPTS[@]}" "$1".asciidoc)
    # Print command in pastable format:
    printf '%q ' "${cmd[@]}"
    printf '\n'
    # Execute it
    "${cmd[@]}"
    

    Make sure not to use eval:

    eval "$cmd" #noooo
    

    This will appear to work with your code as you posted it, but has caveats and security problems.