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 ….
Print to stderr
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.