Text processing · bash builtin
echo
Print its arguments separated by spaces, followed by a newline.
echo [-neE] [STRING...]
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
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"
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"
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"
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"
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'
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'
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"
[-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'
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
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
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 $?"
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 $varwithout quotes splits the value on whitespace and expands any*or?in it. Writeecho "$var".Scripts with
#!/bin/shrun under dash on Debian and Ubuntu, whereecho -eprints-eand backslashes are always interpreted. Useprintfin portable scripts.echo "$data"misbehaves when the data is-n,-eor contains backslashes (in dash or withshopt -s xpg_echo).printf '%s\n' "$data"is always exact.echo -nis not POSIX: someshimplementations print-n. For a prompt without a newline, useprintf '%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/shis bash in POSIX mode, whose echo interprets escapes like dash does. The macOS/bin/echosupports-nbut not-e.GNU
/bin/echosupports-n,-eand-E, like the bash builtin;--helpand--versionwork only whenPOSIXLY_CORRECTis 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).
| Option | What it does |
|---|---|
-n | Do not print the trailing newline. |
-e | Interpret backslash escapes such as \n and \t (bash, GNU). |
-E | Do not interpret backslash escapes (the bash default). |
Related
printfPrint text and values through a format string, with precise control over spacing, numbers and escapes.catConcatenate files and print them to standard output; also the quickest way to see a short file.teeCopy standard input to standard output and to one or more files at the same time.- QuotingSingle quotes, double quotes, backslashes and $'...', what each protects, and the unquoted-variable bugs they prevent, each shown failing and then fixed.
- POSIX sh vs bashThe bashisms that break when a script runs under dash or another POSIX sh, the exact errors dash prints, and the portable replacement for each.
- Word splittingWhen bash splits expansion results into separate words, how IFS controls it, and why `for line in $(cat file)` does not loop over lines.