1

I just moved to Mac. I'm using a shared shell script that's running in bash. The script itself works, however it is written to produce colored output, and that is broken.

Here's the first two lines from the script:

#!/bin/bash

echo -e -n "\e[0m\e[32mhks>>>\e[2m "
  • My expectation when running it from zsh would be that it produces the output hks>>> in bright green.
  • However, the output that is produced is:
    matthiashuttar@mac hks % hks bla
    \e[0m\e[32mhks>>>\e[2m \e[91mfailed to resolve target\e[0m
    

I know it's not a zsh issue, because I can just execute that echo statement as is in zsh and it will produce the output in the correct green color.

Can someone point me towards what I am missing?

4
  • The shebang selects the correct shell for you; if you run it correctly, it doesn't matter which interactive shell you are starting it from (any more than ls cares whether you run it from Bash, Zsh, or Python).
    – tripleee
    Commented Jan 3, 2023 at 14:53
  • The actual symptom suggests that you are running it in a terminal which does not have color support. (The proper fix is to use tput instead of bare escape codes.) What is the output of echo "$TERM"?
    – tripleee
    Commented Jan 3, 2023 at 14:55
  • found a solution - using printf instead of echo -e worked. just that i do not understand the problem...? echo $TERM is xterm-256color
    – Matthias
    Commented Jan 3, 2023 at 15:39
  • echo -e is nonstandard, but the symptom suggests that you are running the script incorrectly. Running it with zsh or . will bypass the shebang and force-feed it to Zsh; don't do that.
    – tripleee
    Commented Jan 3, 2023 at 16:16

1 Answer 1

0

MacOS ships an ancient version of bash (3.2.x), so bash scripts that work on other systems might not work on macOS. The version of bash on macOS does not support \e as an escape sequence in echo.

This appears to be a bug in bash 1.x through 3.x, fixed in 4.0. The manual lists \e as one of the escape sequences supported by echo, but help echo lists \E and not \e. (Though digging into the code I can't see where \e and \E are treated differently — but experimentally, they are.)

(There's definitely a bug because of the inconsistency. But I think back then supporting only \E was the desired behavior, presumably because it was a nonstandard extension and there's a habit in shell circles, mostly coming from command line options, that lowercase letters are standard things and uppercase letters are nonstandard things or modern additions. So the bug was that the manual wrongly listed \e.)

printf and $'…' use different code for backslash escapes, and both recognize \e even in bash 3.2.x. Alternatively, you can use an octal escape sequence, which works in all sh-style shells.

So any of the following will work instead of echo -e -n '\e…':

  • echo -e -n '\033…' (works in most sh-style shells, but some don't support -e or -n as an option)
  • printf '\033…' (note that any % must be doubled; use %s and an extra argument if there's a variable) (works in all sh-style shells)
  • printf %b '\033…' (works in all sh-style shells)
  • printf '\e…' (note that any % must be doubled; use %s and an extra argument if there's a variable)
  • printf %b '\e…'
  • echo -n $'\e…'
  • echo -n -e '\E…'
6
  • echo -n -e '\E…' isn't working for me either in macOS' builtin version of bash (v3.2.57), though I haven't tested in the latest version of macOS itself. BTW, another option would be printf %b '\e…' (the %b format translates escape sequences in the string). Commented Jan 5, 2023 at 5:15
  • The Bash on my Mac is "3.2.57(1)-release", and indeed echo -e '\e' doesn't work there. But it does work with the exact same version I've compiled from the source on Linux... I don't see a mention of that in the changelog after Bash 3.2 either, so I wonder if the version on Mac just has broken it. The NEWS file lists "nn. The `echo' builtin has a new escape character: \e." as a new feature in Bash 2.0.
    – ilkkachu
    Commented Jan 5, 2023 at 10:22
  • I'd expect the echo of macos (and the echo builtin of its sh) to output -e -n <ESC>…<newline> for echo -e -n '\033…' since it's UNIX certified. Commented Jan 5, 2023 at 10:49
  • \e is unspecified by POSIX in anycase, printf '\33' to print an ASCII-encoded ESC. Commented Jan 5, 2023 at 10:50
  • 1
    printf '%b' '\033…' works in any shell on POSIX systems, not just sh-based ones. Some sh implementations don't have printf builtin. Commented Jan 5, 2023 at 10:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .