Home / Alt manpages / echo(1)

  • echo(1)
  • User command
  • linux

Use GNU echo Safely for Simple Shell Output

You will finish with a reliable way to print text from a shell script, choose whether a final newline is present, and interpret the small set of escape sequences supported by the installed GNU command. You will also know when the shell is calling a builtin instead, and when printf is the safer choice.

Allow about ten minutes. You need a POSIX-like shell and the GNU coreutils package. The examples use GNU coreutils 9.4, installed here as package version 9.4-3ubuntu6.3. No command in this guide needs elevated privileges. Nothing changes on disk or in system configuration.

1. Check which echo you are running

Start by checking the command resolution in your current shell:

$ type -a echo
echo is a shell builtin
echo is /usr/bin/echo
echo is /bin/echo

A shell builtin normally takes precedence over /usr/bin/echo. Builtins differ between shells, especially around options and backslash escapes. If a script needs the GNU behaviour documented here, call the external command explicitly:

$ command -v /usr/bin/echo
/usr/bin/echo
$ dpkg-query -W coreutils
coreutils 9.4-3ubuntu6.3

The package version is host-specific. Run the check on the machine where the script will run rather than copying this version into a compatibility assumption.

Checkpoint

Use plain echo for an interactive shell experiment, or use /usr/bin/echo when the GNU implementation itself is part of the test.

2. Print ordinary text with the default newline

GNU echo writes all its arguments to standard output, separating arguments with single spaces, then writes a trailing newline. Quote a phrase when you want the shell to pass it as one argument:

$ /usr/bin/echo 'backup complete'
backup complete
$ /usr/bin/echo 'two words' 'and three'
two words and three

Without quotes, the shell performs word splitting before echo receives the text. That usually still produces spaces between words, but it can also expand wildcards or remove repeated whitespace. Quoting is a shell rule, not an echo option, and it is the simplest way to keep data together.

Variables need the same care. Double quotes expand a variable while preserving its internal whitespace; single quotes print the dollar sign literally:

$ message='report ready at 09:30'
$ /usr/bin/echo "$message"
report ready at 09:30
$ /usr/bin/echo '$message'
$message

Do not put untrusted data into an unquoted command line. An unquoted value can undergo pathname expansion, and data beginning with an option can be mistaken for a request to change echo's behaviour.

3. Suppress the trailing newline when a protocol needs it

Use -n when the output must end immediately after the last character:

$ /usr/bin/echo -n 'waiting'
waiting$ /usr/bin/printf '\n'

The prompt appears on the same line because echo did not terminate its output. This is useful for small interactive displays, but it can make logs and command output difficult to read. It also makes the next command's output share the same line unless that command writes a newline.

Check the byte-level result when the final newline matters:

$ /usr/bin/echo -n 'waiting' | od -An -t x1
 77 61 69 74 69 6e 67

The hexadecimal bytes are the letters in waiting; there is no final 0a byte. This is an ordinary read-only pipeline.

4. Interpret backslash escapes deliberately

GNU echo disables backslash interpretation by default. With no option, the characters \n remain two characters:

$ /usr/bin/echo 'first\nsecond'
first\nsecond

Use -e to enable the escape sequences listed by the installed manpage:

$ /usr/bin/echo -e 'first\nsecond\tready'
first
second  ready

The supported forms include \n for a newline, \t for a horizontal tab, \r for a carriage return, \\ for a backslash, \a for an alert, and \c to stop output without writing the usual final newline. GNU echo also accepts octal bytes as \0NNN, with one to three octal digits, and hexadecimal bytes as \xHH, with one or two hexadecimal digits.

Use -E to state the default explicitly and keep the backslashes literal:

$ /usr/bin/echo -E 'path\tname'
path\tname

Do not rely on -e behaving identically in every shell's builtin. If the exact bytes matter in a script, prefer printf, whose format and arguments are designed for this job.

5. Keep option-like data from changing the command

The GNU manpage warns that echo has issues with strings that look like options. A value such as -n is not reliably distinguishable from the no-newline option when it is passed as the first argument:

$ /usr/bin/echo -n
$ /usr/bin/echo -- '-n'
-- -n

The second command demonstrates a GNU-specific escape from that ambiguity: -- is printed as data here, rather than acting as a portable option terminator. It does not turn echo into a generally safe argument printer. For data that may begin with a hyphen, use printf with a fixed format:

$ value='-n'
$ /usr/bin/printf '%s\n' "$value"
-n

The format string is controlled by the script, while the value is always treated as text. This also avoids accidentally interpreting percent sequences in the value as formatting instructions.

6. Verify scripts without changing state

Use the built-in help and version options to confirm the installed interface:

$ /usr/bin/echo --version | head -1
echo (GNU coreutils) 9.4
$ /usr/bin/echo --help | head -4
Usage: /usr/bin/echo [SHORT-OPTION]... [STRING]...
  or:  /usr/bin/echo LONG-OPTION
Echo the STRING(s) to standard output.

Help text can vary with packaging and locale, so check the option names rather than depending on every line matching this example. A non-zero status from a larger pipeline can also be hidden by a later command unless the shell's pipeline settings are configured appropriately. For a simple output test, inspect the result directly and then check the command status:

$ /usr/bin/echo 'echo-ok'
echo-ok
$ printf 'exit status: %s\n' "$?"
exit status: 0

Echo does not need root. Adding sudo does not improve output and can make ownership, auditing and troubleshooting less clear. If output is being redirected to a protected file, solve the permission problem deliberately; do not make an entire script run as root just to print a message.

Done means

  • You checked whether your shell resolves echo to a builtin or the GNU external command.
  • You can produce normal output with a trailing newline and can verify the result.
  • You use -n, -e and -E only when their output effect is intentional.
  • You know that option-like data can confuse echo and use printf '%s\n' for reliable text output.
  • You have not used elevated privileges or changed persistent system state.