Search code examples
zshoh-my-zsh

Error displaying apostrophes in ASCII


I'm making a custom zsh theme for when you open up your terminal. I'm not that new to using oh-my-zsh but I am new to zsh documentation.

Here's what I'm having problems with:

wolf='               
           .-'''''-.
         .'         `.
        :             :
       :               :
       :      _/|      :
        :   =/_/      :
         `._/ |     .'
      (   /  ,|...-'
       \_/^\/||__
    _/~  `""~`"` \_
 __/  -'/  `-._ `\_\__
/     /-'`  `\   \  \-.\\

'


print -P $wolf

When I try it in terminal I get two errors:

  1. /Users/User/.oh-my-zsh/themes/wolf.zsh-theme:4: no such file or directory: . .\n : :\n : :\n : _/| :\n : =/_/ :\n._/ |

  2. /Users/User/.oh-my-zsh/themes/wolf.zsh-theme:31: parse error near `\n

I'm guessing that these errors have to do with the apostrophes in the ASCII art.


Solution

  • The issue here (as jdv noted in his comment) is quoting.

    In zsh:

    • it is not possible to use single-quotes (') withing single-quoted text. Any text within two single-quotes is taken verbatim, no additional quoting is possible. Single quotes can only be quoted with a preceding backslash or inside double quotes.
    • Within double-quotes (") backticks (`), dollar signs ($) and backslashes (\) are treated specially, and need to be quoted with a preceding backslash.

    As quite a lot of these characters appear in your ASCII-art, you have to make sure, that they are all quoted properly.

    Additionally, you use the builtin print, which by default also interprets \ as escape character.

    There are two basic solutions:

    • Fully quote the string and use print -r or echo -E to print the text. In both cases the parameter disables escape sequence handling.

      The easiest way to achieve full quoting is probably to keep the surrounding single-quotes and replace any ' within with '\''. At every occurrence this closes the previous single-quoted text, adds a quoted single-quote and starts a new single-quoted text. Any other special character is then quoted within single quotes.

      wolf='               
                 .-'\'''\'''\'''\'''\''-.
               .'\''         `.
              :             :
             :               :
             :      _/|      :
              :   =/_/      :
               `._/ |     .'\''
            (   /  ,|...-'\''
             \_/^\/||__
          _/~  `""~`"` \_
       __/  -'\''/  `-._ `\_\__
      /     /-'\''`  `\   \  \-.\\
      
      '
      print -r $wolf
      
    • Use a here-document with cat to avoid the whole quoting issue:

      cat <<'END'
                 .-'''''-.
               .'         `.
              :             :
             :               :
             :      _/|      :
              :   =/_/      :
               `._/ |     .'
            (   /  ,|...-'
             \_/^\/||__
          _/~  `""~`"` \_
       __/  -'/  `-._ `\_\__
      /     /-'`  `\   \  \-.\\
      
      END
      

      Note the single quotes around 'END'. This needs to be done in order to disable parameter substitution ($FOO) and command substitution ($(command) or `command`) inside the here-document.