23

I would like to output this on completion of my bash script.

 /\_/\
( o.o )
 > ^ <

I have tried the following but all return errors.

echo /\\_/\\\n\( o.o \)\n > ^ <
echo  \/\\_\/\\\r\n( o.o )\r\n > ^ <
echo /\\_/\\\n\( o.o \)\n \> ^ <

How do I escape these characters so that bash renders them as a string?

  • 4
    I can't help wondering whether there is a meaning to the output, or whether it's a useless use of cat – IMSoP Nov 26 '21 at 18:21
  • It's probably a UUoC but as long as you aren't relying on ASCII art elsewhere in your program then it should be OK :D For me, there is no meaning to the output on this occasion, I just wanted to echo a cat on termination. – James Geddes Nov 26 '21 at 19:30
  • 1
    @IMSoP This is a very useful use of a cat! – Thorbjørn Ravn Andersen Nov 27 '21 at 12:59
  • I think the title should be changed (maybe?). This is something really useful for some, as the question itself is about outputting a multi-line string with slashes and white-space. However, I fail to come up with something interesting. The current title is, in my opinion, inadequate. There's no "conversion" going on, specially "to bash echo" (how does one convert something to "echo" anyway?). However, in my opinion, the title is intriguing enough to make it a very visited post. I don't know how to feel about the title... – Ismael Miguel Nov 27 '21 at 20:55
  • 1
    @IsmaelMiguel agreed - if you can think of a better one feel free to change it – James Geddes Nov 28 '21 at 11:31
  • @JamesGeddes That's my problem ... I don't have any ideas for a better title :/ – Ismael Miguel Nov 29 '21 at 07:52
  • @IsmaelMiguel how is that? – James Geddes Nov 29 '21 at 10:27
  • 1
    @JamesGeddes I'm bad at titles... What you wrote is way better than anything I can come up with. – Ismael Miguel Nov 30 '21 at 07:30

2 Answers2

41

In this case, I'd use cat with a (quoted) here-document:

cat <<'END_CAT'
 /\_/\
( o.o )
 > ^ <
END_CAT

This is the best way of ensuring the ASCII art is outputted the way it is intended without the shell "getting in the way" (expanding variables etc., interpreting backslash escape sequences, or doing redirections, piping etc.)

You could also use a multi-line string with printf:

printf '%s\n' ' /\_/\
( o.o )
 > ^ <'

Note the use of single quotes around the static string that we want to output. We use single quotes to ensure that the ASCII art is not interpreted in any way by the shell. Also note that the string that we output is the second argument to printf. The first argument to printf is always a single quoted formatting string, where backslashes are far from inactive.

Or multiple strings with printf (one per line):

printf '%s\n' ' /\_/\' '( o.o )' ' > ^ <'
printf '%s\n' \
' /\_/\' \
'( o.o )' \
' > ^ <'

Or, with echo (but see Why is printf better than echo? ; basically, depending on the shell and its current settings, there are possible issues with certain escape sequences that may not play nice with ASCII drawings),

echo ' /\_/\
( o.o )
 > ^ <'

But again, just outputting it from a here-document with cat would be most convenient and straight-forward I think.

Kusalananda
  • 333,661
16

Quote it with single '' or double quotes "" to prevent the <>() from being taken as operators. Then if you want it on one line, use echo -e or $' ' in Bash, mark the newlines as \n and escape the backslashes with another backslash. Or rather use printf to avoid issues with the differences between echo in various environments.

So:

$ printf ' /\\_/\\\n( o.o )\n > ^ <\n'
 /\_/\
( o.o )
 > ^ <
$ printf "%s\n" $' /\\_/\\\n( o.o )\n > ^ <'
 /\_/\
( o.o )
 > ^ <  

See also:

ilkkachu
  • 138,973