echo prints its arguments followed by a newline. It’s how scripts show messages, write lines to files and display variables. Quoting decides what it actually prints.

Basics

echo Hello, world
echo "Home directory: $HOME"
echo "Today is $(date +%F)"
echo                         # prints an empty line

Quoting

Form $VAR and $(cmd) expanded? Use
echo "text $VAR" Yes Normal choice
echo 'text $VAR' No, printed literally Literal dollars, backslashes
echo text $VAR Yes, but split on spaces and globbed Avoid with variables

Without quotes, multiple spaces collapse and * expands to filenames:

msg="a    b  *"
echo $msg      # a b file1 file2 …
echo "$msg"    # a    b  *

Always quote variables you pass to echo and other commands.

Options: -n and -e

echo -n "Enter name: "            # no trailing newline
echo -e "line1\nline2\tTabbed"    # interpret backslash escapes

Escapes recognised with -e: \n newline, \t tab, \\ backslash, \e or \033 escape (for colours), \c stop output.

Write to files

echo "export EDITOR=vim" >> ~/.bashrc       # append
echo "127.0.0.1 app.local" | sudo tee -a /etc/hosts > /dev/null
echo "" > file.log                          # leaves a single newline in the file
: > file.log                                # empty the file completely

sudo echo x > /root/file fails because the redirect isn’t run as root. Use sudo tee instead. See tee.

Writing to kernel settings:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

This change is temporary. Make it permanent in /etc/sysctl.d/.

Colours in scripts

RED='\033[0;31m'; GREEN='\033[0;32m'; NC='\033[0m'
echo -e "${GREEN}OK${NC} backup finished"
echo -e "${RED}ERROR${NC} disk full"

Only add colour when output goes to a terminal: if [ -t 1 ]; then ….

Errors should go to standard error, so they don’t mix with data on stdout:

echo "error: config not found" >&2

Why printf is often better

echo behaves differently across shells and systems. sh versus bash, and BSD versus GNU, treat -e, -n and backslashes differently. It can’t print a string that starts with -n reliably either. printf is consistent everywhere:

printf '%s\n' "$var"                  # safe for any content
printf 'Name: %s, Age: %d\n' "$name" "$age"
printf '%-20s %8s\n' "Disk" "Used"    # aligned columns
printf '%.2f\n' 3.14159               # 3.14

Rule of thumb: use echo for fixed messages and printf for printing variables of unknown content, formatting, and in portable #!/bin/sh scripts.

Handy one-liners

echo $SHELL                                  # current login shell
echo $PATH | tr ':' '\n'                     # PATH, one directory per line
echo "$?"                                    # exit status of the last command
echo {1..5}                                  # 1 2 3 4 5 (brace expansion)
echo *.conf                                  # quick file listing via glob
echo "secret" | base64                       # encode
echo "c2VjcmV0Cg==" | base64 -d              # decode
echo -n "text" | sha256sum                   # hash without a trailing newline

The -n in the last line matters. Without it, the newline becomes part of the hashed text.

Quick reference

Task Command
Print text echo "text"
No newline echo -n "text"
Interpret \n, \t echo -e "a\nb"
Append to file echo "x" >> file
Write as root echo "x" | sudo tee -a file
To stderr echo "msg" >&2
Safe for any string printf '%s\n' "$var"

Related: Bash variables, environment variables and Bash scripting.

  • Linux
  • Bash
  • Command Line