16

I have a shell script that uses the following to print a green checkmark in its output:

col_green="\e[32;01m"
col_reset="\e[39;49;00m"

echo -e "Done ${col_green}✓${col_reset}"

After reading about Bash's ANSI-C Quoting, I realized I could use it when setting my color variables and remove the -e flag from my echo.

col_green=$'\e[32;01m'
col_reset=$'\e[39;49;00m'

echo "Done ${col_green}✓${col_reset}"

This seems appealing, since it means the message prints correctly whether it's passed to Bash's builtin echo or the external util /bin/echo (I'm on macOS).

But does this make the script less portable? I know Bash and Zsh support this style of quoting, but I'm not sure about others.

αғsнιη
  • 40,939
  • 15
  • 71
  • 114
ivan
  • 1,858
  • 2
  • 19
  • 37
  • Yes, since when only ksh and its variations support it for now. But IIRC, ANSI-C quoting is going to be in next POSIX spec. – cuonglm Jun 18 '17 at 17:41
  • ksh doc: [debian ksh(1)](https://manpages.debian.org/buster/ksh/ksh.1.en.html#Quoting.) – Mingye Wang Mar 02 '20 at 14:26

2 Answers2

19

$'…' is a ksh93 feature that is also present in zsh, bash, mksh, FreeBSD sh and in some builds of BusyBox sh (BusyBox ash built with ENABLE_ASH_BASH_COMPAT). It isn't present in the POSIX sh language yet. Common Bourne-like shells that don't have it include dash (which is /bin/sh by default on Ubuntu among others), ksh88, the Bourne shell, NetBSD sh, yash, derivatives of pdksh other than mksh and some builds of BusyBox.

A portable way to get backslash-letter and backslash-octal parsed as control characters is to use printf. It's present on all POSIX-compliant systems.

esc=$(printf '\033') # assuming an ASCII (as opposed to EBCDIC) system
col_green="${esc}[32;01m"

Note that \e is not portable. It's supported by many implementations of printf but not by the one in dash¹. Use the octal code instead.

¹ It is supported in Debian and derivatives that ship at least 0.5.8-2.4, e.g. since Debian stretch and Ubuntu 17.04.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • are you sure about `\e` not being supported in `dash`? `dash -c 'printf "\e[1;31m"; type printf; printf "\e[m"'` will print `printf is a shell builtin` in bold red here (dash-0.5.8). A shell that doesn't support `\e` is `yash`. –  Feb 19 '19 at 17:35
  • @mosvy Prints `\e[1;31mprintf is a shell builtin \e[m` here. Ubuntu 16.04, dash 0.5.8-2.1ubuntu2. Prints in red on Ubuntu 18.04 with dash 0.5.8-2.10. Looks like Ubuntu made a patch to support it. – Gilles 'SO- stop being evil' Feb 19 '19 at 17:46
  • Yeah, sorry, it looks that's a debian (9.7 stretch) patch. [here](https://www.mail-archive.com/[email protected]/msg01722.html)'s the original. –  Feb 19 '19 at 17:54
0

The degree of $'...' support also needs to be taken into consideration when porting. The POSIX Folks' proposal to put this in POSIX sh mentions one in particular:

stephane: ksh93 is the shell $'...' comes from (while $'\uxxxx' [and $'\Uxxxxxxxx'] comes from zsh: http://www.zsh.org/mla/workers/2003/msg00223.html) [^]

From what I got here on my Debian bullseye, the ksh2020 understands $'\U1F600'. This is the only "official" Korn shell I can get on this new distro.

mksh parsed it but botched it entirely with a U+FFFE. Since it did not complain about a syntax error there's gotta be something wrong with it's understanding of Unicode. It handles $'\U01F60' just fine.

Mingye Wang
  • 1,181
  • 9
  • 23
  • Unfortunately, as an effect of a recent [coup](https://github.com/att/ast/issues/1466) ksh2020 has been disappeared. But yes, the original ksh93 does support `$'...'` and iirc it was the first who did. –  Mar 02 '20 at 14:48
  • @Arthur2e5. `ksh2020` is not from AT&T. A couple of people, one from Red Hat, essentially hijacked the AT&T AST github tree a few years ago and claimed control of future `ksh93` development – fpmurphy Mar 02 '20 at 15:41