32

I've read the man pages on echo, and it tells me that the -e parameter will allow an escaped character, such as an escaped n for newline, to have its special meaning. When I type the command

$ echo -e 'foo\nbar'

into an interactive bash shell, I get the expected output:

foo
bar

But when I use this same command (i've tried this command character for character as a test case) I get the following output:

-e foo
 bar

It's as if echo is interpretting the -e as a parameter (because the newline still shows up) yet also it interprets the -e as a string to echo. What's going on here? How can I prevent the -e showing up?

4 Answers4

40

You need to use #!/bin/bash as the first line in your script. If you don't, or if you use #!/bin/sh, the script will be run by the Bourne shell and its echo doesn't recognize the -e option. In general, it is recommended that all new scripts use printf instead of echo if portability is important.

In Ubuntu, sh is provided by a symlink to /bin/dash.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • Oh that's it. I had !#/bin/sh, which was obviously running in Bourne but my interactive shell was Bash. Cheers. – Sam Svenbjorgchristiensensen Dec 14 '10 at 09:35
  • how to solve the same problem in python? I would like to to print os.system("echo -e '\x41'") but it is having the same issue – Sarvar Nishonboyev Mar 13 '17 at 00:01
  • @SarvarNishonboyev: I assume there must be some reason that you don't just have Python output the string directly. The reason it's doing this is because Python using a `/bin/sh` which doesn't support `-e`. In order to use Bash, use `subprocess` as described in the answers [her](http://stackoverflow.com/questions/21822054/how-to-force-os-system-to-use-bash-instead-of-shell). But try instead to use Python's output capability directly instead. – Dennis Williamson Mar 13 '17 at 16:06
  • @DennisWilliamson pretty nice answer, thanks. I would use python's internal output function but there are some issues I faced, I'm afraid it would be long to describe it here :) I'm running vulnerable c program from pyhton in order to attack (it's my coursework). c program receive input from user using scanf, so I used os.system('echo -e "\x41.." | ./vulnerable ') command. – Sarvar Nishonboyev Mar 13 '17 at 21:51
7

Different implementations of echo behave in annoyingly different ways. Some don't take options (i.e. will simply echo -e as you describe) and automatically interpret escape sequences in their parameters. Some take flags, and don't interpret escapes unless given the -e flag. Some take flags, and interpret different escape sequences depending on whether the -e flag was passed. Some will cause you to tear your hair out if you try to get them to behave in a predictable manner... oh, wait, that's all of them.

What you're probably seeing here is a difference between the version of echo built into bash vs /bin/echo or maybe vs. some other shell's builtin. This bit me when Mac OS X v10.5 shipped with a bash builtin echo that echoed flags, unlike what all my scripts expected...

In any case, there's a solution: use printf instead. It always interprets escape sequences in its first argument (the format string). The problems are that it doesn't automatically add a newline (so you have to remember do that explicitly), and it also interprets % sequences in its first argument (it is, after all, a format string). Generally, you want to put all the formatting stuff in the format string, then put variable strings in the rest of the arguments so you can control how they're interpreted by which % format you use to interpolate them into the output. Some examples:

printf "foo\nbar\n"      # this does what you're trying to do in the example
printf "%s\n" "$var"     # behaves like 'echo "$var"', except escapes will never be interpreted
printf "%b\n" "$var"     # behaves like 'echo "$var"', except escapes will always be interpreted
printf "%b\n" "foo\nbar" # also does your example
Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
2

Use

alias echo /usr/bin/echo

to force 'echo' invoking coreutils' echo which interpret '-e' parameter.

Huang F. Lei
  • 1,835
  • 15
  • 23
0

Try this:

import subprocess

def bash_command(cmd):
    subprocess.Popen(['/bin/bash', '-c', cmd])

code="abcde"
// you can use echo options such as -e
bash_command('echo -e "'+code+'"')

Source: http://www.saltycrane.com/blog/2011/04/how-use-bash-shell-python-subprocess-instead-binsh/

Sarvar Nishonboyev
  • 12,262
  • 10
  • 69
  • 70