opscape

Text processing · bash builtin

echo

Print its arguments separated by spaces, followed by a newline.

echo [-neE] [STRING...]

12 of 12 examples run in Debian 13.7 on 2026-10-31 · manual: echo(1)

echo prints its arguments with a single space between them and a newline at the end. It is the first command everyone learns and is fine for fixed messages and for quickly looking at a variable. Every shell has it as a builtin, and coreutils provides /bin/echo as well.

The catch is that echo is not one command but several that disagree. bash's echo ignores backslash escapes unless you pass -e; dash (/bin/sh on Debian and Ubuntu) always interprets them and does not know -e at all, so it prints it. And no echo can reliably print a string that starts with - or contains backslashes, because it may be taken as an option or an escape.

The rule that follows: use echo for literal text you wrote yourself, and printf for anything that contains data, needs escapes, or must behave the same under sh and bash.

Examples

Print a message

echo Hello, world
explain
output
Hello, world

The two arguments Hello, and world are printed with one space between them and a newline after.

Print a variable

name="Alice Moreau"; echo "user: $name, home: $HOME"
explain
output
user: Alice Moreau, home: /home/dev

Variables inside double quotes are expanded. Single quotes would print $name literally.

Quotes keep spacing intact

echo a    b      c
echo "a    b      c"
output
a b c
a    b      c

Unquoted, the shell splits the line into three words and echo joins them with single spaces. Quoted, it is one argument and the spaces survive.

Unquoted variables are split and globbed

pattern='*.txt'
echo $pattern
echo "$pattern"
output
file with spaces.txt notes.txt todo.txt
*.txt

Unquoted, $pattern undergoes filename expansion, so echo prints the matching files rather than the pattern. Always quote variables, even in echo.

Leave off the trailing newline with -n

echo -n "no newline here"; echo " <- same line"
explain
output
no newline here <- same line

-n suppresses the newline, so the next output continues on the same line. bash and dash both support -n, but POSIX does not require it; printf '%s' is the portable form.

Interpret escapes with -e in bash

echo 'col1\tcol2'
echo -e 'col1\tcol2\nnext line'
output
col1\tcol2
col1	col2
next line

bash's echo prints backslashes literally by default. -e turns on escapes such as \t (tab) and \n (newline).

The same commands under sh behave differently

echo 'col1\tcol2'
echo -e 'col1\tcol2'
output
col1	col2
-e col1	col2

Under dash, the /bin/sh on Debian and Ubuntu, echo always interprets escapes, so the first line gets a real tab. dash's echo has no -e option, so the second line prints -e as text. A script that works in bash can print different output when run as sh script.sh.

Echo cannot print some strings

flag='-n'
echo "$flag"
echo "[$flag]"
printf '%s\n' "$flag"
output
[-n]
-n

bash's echo treats an argument that is exactly -n, -e or -E as an option, even from a quoted variable, so the first line prints nothing at all (not even a newline, as -n means). Wrapping it in other text or using printf '%s\n' prints it correctly.

Use $'...' quoting instead of -e

echo $'name:\tAlice\nrole:\tadmin'
explain
output
name:	Alice
role:	admin

bash's $'...' quoting turns escapes into real characters before echo sees them, so no option is needed. It works in bash, zsh and ksh, but not in the dash 0.5.12 that is /bin/sh on Debian 13, where $'...' is just a $ followed by a quoted string.

Write and append to a file

echo "first" > out.txt
echo "second" >> out.txt
cat out.txt
output
first
second

> creates or truncates the file and >> appends. The redirection is done by the shell, not by echo.

Preview an expansion before running it

echo mv data/{numbers,primes}.txt
echo rm logs/*.log
output
mv data/numbers.txt data/primes.txt
rm logs/app.log logs/error.log

Putting echo in front of a command prints what the shell would run after brace expansion and globbing, without running it. A cheap dry run before a destructive command.

Print the exit status of the last command

grep -q CRITICAL logs/app.log; echo "grep returned $?"
explain
output
grep returned 1

$? holds the status of the most recent command, 1 here because nothing matched. Read it right away: the echo itself resets it.

Common pitfalls

  • echo $var without quotes splits the value on whitespace and expands any * or ? in it. Write echo "$var".

  • Scripts with #!/bin/sh run under dash on Debian and Ubuntu, where echo -e prints -e and backslashes are always interpreted. Use printf in portable scripts.

  • echo "$data" misbehaves when the data is -n, -e or contains backslashes (in dash or with shopt -s xpg_echo). printf '%s\n' "$data" is always exact.

  • echo -n is not POSIX: some sh implementations print -n. For a prompt without a newline, use printf '%s' "Continue? ".

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • macOS /bin/sh is bash in POSIX mode, whose echo interprets escapes like dash does. The macOS /bin/echo supports -n but not -e.

  • GNU /bin/echo supports -n, -e and -E, like the bash builtin; --help and --version work only when POSIXLY_CORRECT is unset and the option is the sole argument.

Options worth knowing

A selection, described in our own words. For the full list, see echo(1).

OptionWhat it does
-nDo not print the trailing newline.
-eInterpret backslash escapes such as \n and \t (bash, GNU).
-EDo not interpret backslash escapes (the bash default).

Related