I would like to print a check mark and a cross mark in a shell script:
#!/bin/bash echo -e "\xE2\x9C\x94 existing" echo -e "\xE2\x9D\x8C missing"
Why isn't this working?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
As revealed by the OP in the comments, they were calling script with
sh file.sh. Depending on the default shell to which
/bin/sh is symlinked it might not support unicode characters.
For instance, on Ubuntu , the default shell is
$ dash $ printf "\xE2\x9C\x94 missing\n" \xE2\x9C\x94 missing $ echo -e "\xE2\x9C\x94" -e \xE2\x9C\x94
The reason why it worked when you called the command in interactive shell, is because users interactive shell is by default (on Ubuntu)
To properly run the script, you need to either:
Alternatively, one could resort to shell-independent methods:
# this printf is standalone program, not shell built-in $ /usr/bin/printf "\xE2\x9C\x94 check mark\n" ✔ check mark $ python -c 'print "\xE2\x9C\x94 check mark"' ✔ check mark $ perl -e 'print "\xE2\x9C\x94 check mark"' ✔ check mark
\xE2\x9C\x94 is the UTF-8 encoding of the U+2714 (heavy check mark) character.
Those 3 bytes will only be displayed as a check mark if the terminal's character set is UTF-8 (and uses a font that has that character).
For terminal emulators, the charset they use will typically be the one in the locale at the time they were started. Unless you have changed the locale within the shell started in that terminal, you can tell which one it was with:
printf implementations including GNU
printf and the
printf builtin of
lksh (a more POSIX compatible variant of
mksh on Debian-based systems at least) support:
$ printf '\u2714\u274c\n' ✔❌
To print those characters in the correct encoding for the locale's charset (ksh93's
printf builtin also supports that
\uXXXX notation but always outputs in UTF-8 regardless of the locale's charset). Shells whose
printf builtin support it and have an
echo that expands escape sequences (possibly with
-e) typically also support
Now, AFAICT, the only two charsets where those two U+274C and U+2714 characters are available on a typical GNU system are UTF-8 and GB18030. In locales using different charsets,
printf will not be able to display those characters as they simply don't exist. Depending on the implementation,
printf will print
\u274C literally or fail with an error.
Some shells (
zsh where it originated,
sh) also support that
\uXXXX notation in their
So you can do:
Depending on the shell, those will be expanded to the locale's encoding that was in effect at the time the command was parsed (
bash) or at the time it was run (
zsh) or in UTF-8 always (ksh).
POSIXly (portably among Unix-like systems), if you want to print arbitrary sequences of bytes, you'll want to use
printf and the octal notation.
\xE2\x9C\x94 (the UTF-8 encoding of U+2714) would be printed on a line portably with:
And if you wanted it to be converted to the correct encoding for the locale, that would be:
printf '\342\234\224\n' | iconv -f UTF-8
POSIX doesn't specify which character encoding may be supported on a system, nor their name, but the above command would typically work on POSIX systems that support the UTF-8 encoding.