9

I know that echo -e is not an ordinary command. I have tried echo '-e' and echo \-e but they still don`t work.

  • 1
    What do you mean with 'not an ordinary command line'? echo is usually a shell builtin, but there is usually also /usr/bin/echo. The -e is not POSIX, but available e.g. with bash. Please give more details what you mean with 'they still don't work'. What is the expected behavior? – maxschlepzig Nov 15 '14 at 10:21
  • I want to print -e using echo. Any suggestions? – Highlights Factory Nov 15 '14 at 10:27
  • 3
    consider using printf, it's more portable. – Michael Durrant Nov 15 '14 at 11:30
  • 1
    Curiously enough, echo -- -e doesn't work either. Conventionally (with GNU utilities at least) the double dash indicates the end of options, with the rest being kept as literal arguments. – Wil Cooley Nov 15 '14 at 16:47
  • @WilCooley, not a huge surprise -- given that echo by its nature needs to treat arguments as data, including those that start with dashes, each and every extension is by its nature a deviation from standard-defined behavior (something that a standards-compliant echo would emit to the screen gracefully, but an extended echo does not). – Charles Duffy Nov 15 '14 at 17:23
  • 6
    echo madness again. If people would only use printf and never look back. – Jens Nov 15 '14 at 18:23

5 Answers5

25

The best solution is not to use echo, but to use printf instead.

printf '%s\n' -e

This works with arbitrary variables:

var=-e
printf '%s\n' "$var"

...meaning you don't need to do any special preparation/modification elsewhere in your code based on the knowledge that a value will be echod.


Incidentally, the POSIX shell command specification for echo acknowledges that it is unportable as implemented, and contains a note on that subject:

It is not possible to use echo portably across all POSIX systems unless both -n (as the first argument) and escape sequences are omitted.

The printf utility can be used portably to emulate any of the traditional behaviors of the echo utility as follows (assuming that IFS has its standard value or is unset):

The historic System V echo and the requirements on XSI implementations in this volume of POSIX.1-2008 are equivalent to:

printf "%b\n" "$*"

The BSD echo is equivalent to:

if [ "X$1" = "X-n" ]
then
    shift
    printf "%s" "$*"
else
    printf "%s\n" "$*"
fi

New applications are encouraged to use printf instead of echo.

(Emphasis added).


That said, on GNU systems, an alternative exists: Requesting standards-compliant behavior.

$ POSIXLY_CORRECT=1 /bin/echo -e
-e
Charles Duffy
  • 1,732
  • 15
  • 22
  • Interestingly, the POSIX note does say that echo -e is portable. It says -n must be avoided, and escape sequences must be avoided. echo -e avoids both. But as you indicate in the last part of your answer, on GNU systems, echo doesn't bother to conform to POSIX at all by default, and POSIX only notes portability across POSIX systems. – hvd Nov 16 '14 at 09:27
  • @hvd, I don't see -e covered in the portion of the spec that I linked to. Could you provide a link or citation that covers it? – Charles Duffy Nov 16 '14 at 16:53
  • It's the lack of a mention that says it. :) It lists the uses that aren't portable, and -e isn't mentioned, so -e is portable (again, across POSIX systems). To be fair, what you quoted is informative, but the normative text says the same thing: "If the first operand is -n, or if any of the operands contain a character, the results are implementation-defined." – hvd Nov 16 '14 at 17:23
  • 2
    @hvd, rather the contrary. To perform as specified, echo needs to emit all arguments with no behavior defined in a contrary way by the standard. Thus -- unlike almost all other command-line tools covered by the POSIX spec -- echo actually specifies behavior for arguments not given: Printing them. There is no room for adding new flags without breaking specification. – Charles Duffy Nov 16 '14 at 17:26
  • 2
    @hvd, ...for that matter, see the OPTIONS section, where it's set out in black and white: Implementations shall not support any options. – Charles Duffy Nov 16 '14 at 17:27
  • Yes, that's exactly what I meant. The OP is interested in printing the string "-e". On POSIX-conforming systems, echo -e does exactly that. – hvd Nov 16 '14 at 17:27
  • Sorry, then -- I quite misunderstood your argument; we are indeed in violent agreement. – Charles Duffy Nov 16 '14 at 17:28
  • I can see how my comments could be read the way you read them, sorry for not having been clearer. Glad it's resolved. :) – hvd Nov 16 '14 at 17:30
10
  • with newline

    echo -en '-e\n'
    
  • without newline

    echo -e '-e\c'
    
  • with spaces around:

    echo '-e '
    echo ' -e'
    
  • using backspace (thanks to Joseph R.):

    echo -e ' \b-e'
    

    (it does output SPC BS - e LF, but when sent to a terminal that's rendered as -e as BS moves the cursor back one column to the left causing - to overwrite the SPC)

The behaviour of bash's echo builtin may depend on bash version. It also depends on the environment (POSIXLY_CORRECT, SHELLOPTS and BASHOPTS variables), the options (posix, xpg_echo), the build options and argv[0] (sh vs bash). Here tested with GNU bash 4.2.53(1), default build, default options, empty environment, invoked as bash. Works also with zsh 5.0.5.

jimmij
  • 47,140
  • 3
    Why do these ugly-to-the-bone obfuscated "workarounds" receive upvotes? Charles Duffy below has the proper answer: use printf and forget about such problems once and for all. – Jens Nov 15 '14 at 18:25
  • Also, echo -e "\0-e". – ctc Nov 15 '14 at 19:31
  • 7
    Jens: because the OP asked how to do it with the echo command. Attitude not necessary. – ctc Nov 15 '14 at 19:32
  • @ctc - What's the logic behind that answer? I'm not questioning whether it works (with the specific versions of echo tested), but it is a bit... interesting... given as NULs act as terminators when given in C strings; I'm curious as to whether it's an accident of implementation or defined behavior that it functions as given. – Charles Duffy Nov 17 '14 at 21:05
  • 1
    echo -e ' \b-e' outputs space-backspace-dash-e. Only displayed in a terminal will it give you the illusion that it is dash-e. – Stéphane Chazelas Nov 30 '14 at 21:31
  • 1
    @CharlesDuffy, echo -e "\0-e" does output NUL-dash-e. It's just that terminals ignore that NUL character (NULs even used to be sent to some terminals (that did not support flow control) to give them time to do other long things like a carriage return. See the section under Delays and Padding in terminfo(5).) – Stéphane Chazelas Dec 01 '14 at 06:47
  • @StéphaneChazelas, ahh. I'm a touch disappointed that I read that incorrectly. That said, using this trick will have ill effects when emitting output anything but a terminal -- especially in cases (like shell command substitutions) where its output is stored in a C string. – Charles Duffy Dec 01 '14 at 14:06
9

With GNU echo's -e with the ASCII codes for the characters:

$ /bin/echo -e '\055'e
-e

055 is the octal ASCII number for - (see man ascii for quick reference).

muru
  • 72,889
  • 1
    /bin/echo is indeed POSIX-specified. However, its interpretation of octal escape sequences is an XSI extension to the baseline specification. – Charles Duffy Nov 15 '14 at 19:36
  • @CharlesDuffy Indeed, I misspoke. +1 for printf (my first thought as well). Given that -e is an extension, however, is there a way to force pure POSIX behaviour on echo? That would eliminate all uncertainty over this, I think. – muru Nov 15 '14 at 19:46
  • 2
    Actually, yes! Exporting POSIXLY_CORRECT=1 will result in POSIX-compliant behavior for GNU's /bin/echo. – Charles Duffy Nov 16 '14 at 06:40
  • +1 Thanks, good to know to keep your scripts portable and "homebrew-Linux-independent" (i. e. also working on a pro workstation at work). – syntaxerror Dec 05 '14 at 20:57
  • @Kusalananda forgot about this. – muru May 16 '17 at 06:44
  • With GNU echo, you can do POSIXLY_CORRECT=1 /bin/echo -e as POSIX currently requires echo -e to output -e<newline>. – Stéphane Chazelas Feb 19 '19 at 10:30
3

While the obvious, standard and recommended solution is to use printf, to do it with echo can be quite tricky depending on the implementation (not as tricky as for -n though).

POSIX.2017 compliant echos

POSIX requires echo -e to output -e<newline>. So it's just

echo -e

there. POSIX compliant echos in that regard (most of them are not POSIX compliant in other regards, the POSIX spec is close to useless when it comes to echo) include:

  • the echo builtin of bash when both the xpg_echo and posix options have been enabled (at runtime or build time like for the /bin/sh of Apple macOS). set -o posix; shopt -s xpg_echo (the posix option can also be enabled if invoked as sh or when POSIXLY_CORRECT or SHELLOPTS=posix is in the environment).
  • the /bin/echo of certified UNIX systems (AIX, macOS, Solaris at least) and most BSDs
  • the echo builtin of dash, ksh88, the Bourne shell, csh, tcsh, posh, rc, es, akanga
  • GNU echo (/bin/echo on GNU systems) when POSIXLY_CORRECT is in the environment.
  • the echo builtin of mksh and some other pdksh-derives when their posix option is enabled.
  • the echo builtin of yash when $ECHO_STYLE is either unset or one of SYSV, XSI, BSD, DASH, RAW

implementations that support -e

Includes echo of research Unix V8 (where it comes from), GNU, busybox, the echo builtin of bash, zsh, pdksh and derivatives, fish, some ash-based shells like busybox sh or the sh of some BSDs, recent versions of ksh93 (on some systems, and with some values of $PATH) with their default settings, yash with $ECHO_STYLE one of GNU or ZSH:

echo -e '-e\n\c'

The implementations that support -e invariably support -n, so:

echo -ne '-e\n'

would work as well.

zsh

zsh's echo is the only implementation that I know that supports an end-of-option marker (-).

echo - -e

Making it the only Bourne-like shell echo that can output arbitrary data (also because it's the only one that supports NUL bytes in its variables and the arguments of its builtins) with echo -E - "$data")

Except for the NUL-byte issue, other implementations that can output arbitrary data are FreeBSD or macOS /bin/echo where you can do:

/bin/echo "$data
\c"

(in that implementation, \c is only recognized at the end, and no other escape sequence is supported).

And yash's:

ECHO_STYLE=RAW echo "$data"

(though note that yash variables can only hold text, so not arbitrary byte sequences in locales where not all sequences of bytes can form valid characters like in those using UTF-8 as their charmap).

2

Use -n to avoid newline:

$ echo -n - && echo e
-e
  • That won't work in zsh where - is the end of option delimiter or on all the echo implementations that don't support -n (those that support -e also support -n though) – Stéphane Chazelas Feb 19 '19 at 10:27