23

I would like to use echo in bash to print out a string of characters followed by only a carriage return. I've looked through the man page and have found that echo -e will make echo interpret backslash escape characters. Using that I can say echo -e 'hello\r' and it will print like this

$>echo -e 'hello\r'
 hello
$>

So it looks like it handled the carriage return properly. I also found echo -n in the man page will stop echo from inserting a newline character and it looks like it works when I do this

$>echo -n 'hello\r'
 hello\r$>

The problem I'm having is in combining both -e and -n. I've tried each of echo -e -n 'hello\r', echo -n -e 'hello\r', echo -en 'hello\r', and echo -ne 'hello\r' and nothing gets printed like so:

$>echo -ne 'hello\r'
$>

Is there something I'm missing here or can the -e and -n options not be used together?

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
seanwatson
  • 1,053
  • 1
  • 9
  • 12
  • `$> echo -ne 'hello\r'` will leave the cursor at the start of the line containing the 'hello'. So if your prompt is longer than the `$>` you have here, it will overwrite the hello. – Mark Reed May 14 '12 at 02:02
  • “nothing gets printed”? Surely you'd get ‘`$>llo`’ because your 2-character prompt-string would not completely overwrite the 5 characters of ‘hello’. Note that ‘carriage return’ isn't the same as ‘new line’ (see `man ascii`). So it seems that you've successfully replaced new line with carriage return yet you're surprised that carriage return doesn't behave like new line. Why did you want to do this? I'm curious. Also, without the quotes the shell interprets the backslash as an escape character so `\r` just becomes `r`. That means your first command actually prints ‘`hellor`’ not ‘`hello`’. – James Haigh Jun 08 '14 at 14:31
  • Did you run these commands on the same shell? `echo -n hello\r` should have outputted exactly the same as `echo -ne hello\r`; they both print ‘`hellor`’ (without a new line, so the prompt appears as ‘`hellor$>`’). The `-e` is irrelevant here because there's no backslash escape after the shell has stripped it. `echo -ne 'hello\r'` or `echo -ne hello\\r` both pass the argument ‘`hello\r`’ to `echo`. – James Haigh Jun 08 '14 at 14:57
  • At the time of this writing, only 1 of your 4 examples seems to have the correct result (though I'm not sure about the leading space), but I don't think that I can edit this question to correct the examples without loosing the original meaning. :-/ – James Haigh Jun 08 '14 at 14:59

5 Answers5

22

I think it's working, you're just not seeing it. This is your command:

$> echo -ne 'hello\r' 

Because of the carriage return (\r), that will leave the cursor at the start of the same line on the terminal where it wrote the hello - which means that's where the next thing output to the terminal will be written. So if your actual prompt is longer than the $> you show here, it will overwrite the hello completely.

This sequence will let you see what's actually happening:

echo -ne 'hello\r'; sleep 5; echo 'good-bye'

But for better portability to other shells, I would avoid using options on echo like that. Those are purely bashisms, not supported by the POSIX standard. The printf builtin, however, is specified by POSIX. So if you want to display strings with no newline and parsing of backslash sequences, you can just use it:

printf '%s\r' 'hello'
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
11

There are numerous different implementations of the echo command. There's one built into most shells (with different behavior for each), and the behavior of /bin/echo varies considerably from one system to another.

Rather than echo, use printf. It's built into bash as well as being available as an external command, and its behavior is much more consistent across implementations. (The major variation is that the GNU coreutils printf recognizes --help and --version options.)

Just use:

printf 'hello\r'
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 2
    +1 `echo` is fine for printing single lines, but as soon as you use any special options or escapes it gets unreliable and unportable. `printf` is much better for anything like this. – Gordon Davisson May 14 '12 at 02:30
  • The question is tagged as bash-specific, though. Seems likely the OP doesn't need portability for their use case. – Mark Reed May 14 '12 at 16:35
7

I'd like you to introduce you to printf.

OP, meet printf. printf. This is the OP...

Whenever you are trying to do anything unusual with output in BASH, you should switch to printf. In fact, I use printf all the time, so my scripts will run under both BASH and Kornshell.

Although BASH and Kornshell are 99% the same, the echo command is different. In Kornshell, it's deprecated, and you're supposed to use the builtin print. However, there's no print in BASH. Using printf solves the problem because it works (sort of) the same in both shells.

Since printf doesn't automatically end each line with a \n, you don't have to worry about how to prevent the \n from being appended. Heck, if you want a \n, you have to put it yourself. In your case:

printf `hello\r`

However, for safety reasons, you should really do this:

printf '%s\r' 'hello'

This is a habit I've gotten into when I'm using printf. Imagine if I want to print out $FOO, and I do this:

printf "$FOO\n"

That will normally work, but what if $FOO has a dash at the beginning, or has a % sign in it. The above won't do what I want to do. However, if I do this:

printf '%s\n' "$FOO"

This will print out $FOO no matter what $FOO has in it.

David W.
  • 105,218
  • 39
  • 216
  • 337
2

POSIX 7 says it is not possible:

If the first operand is -n, or if any of the operands contain a backslash character, the results are implementation-defined.

On Ubuntu 12.04 for example:

  • Bash's built-in echo echo -e '\n' interprets the newline, echo '\n' does not.
  • /bin/sh's built-in echo does not have the -e option, and interprets the newline even without it. This can byte when writing Makefiles, which use /bin/sh by default.

POSIX 7 solution: printf as the others mentioned.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • That's POSIX; OP asked about bash specifically. And the behavior of `echo` *in bash* is well-defined and documented, including the `-e` and `-n` options and the treatment of backslashes. – Mark Reed Jul 27 '16 at 18:21
  • 1
    @Mark Reed I never claimed otherwise. But many Googlers who come here may be interested in the POSIX behavior as well. – Ciro Santilli OurBigBook.com Jul 27 '16 at 18:55
1

Quoting. It's the wave of the future. Always quote.

echo -ne 'hello\r'

Use double quotes if you put a variable inside that you want expanded.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • Quoting doesn't work either. When I use quotes nothing gets printed. I'll update the question for that – seanwatson May 14 '12 at 01:29
  • @swatso33: It works for me. What do you get when you try: `echo "$BASH_VERSION"` – Dennis Williamson May 14 '12 at 01:32
  • Its version `4.2.24(2)-release`. Running on arch linux if it makes a difference. Must just be my version then. Which version do you have it working on? – seanwatson May 14 '12 at 01:34
  • 1
    @swatso33: Bash 2.05b.0(2)-release, 3.2.51(2)-release, 4.0.33(1)-release, 4.1.9(3)-release and 4.2.0(1)-release. Plus ksh 93t+, pdksh v5.2.14 99/07/13.2, mksh KSH R39 2009/08/01 Debian 39.1-3 and zsh 4.3.10. Also, fish 1.23.1 and tcsh 6.14.00 (tcsh doesn't need and can't use `-e` but it interprets escapes by default). – Dennis Williamson May 14 '12 at 02:25