Applies to: Bash 5.2.37 and GNU coreutils 9.7 on Debian 13 (tested); the same on other Linux distributions with Bash
echo prints its arguments followed by a new line. The $ belongs to the shell, not to echo: before echo runs, Bash replaces $name with the value of the variable name. So echo $HOME prints your home folder.
Print text and variables
$ name="Ucartz" $ echo "Hello $name" Hello Ucartz $ echo "Home: $HOME, user: $USER, shell: $SHELL" Home: /root, user: root, shell: /bin/bash $ echo "Path is: $PATH" Path is: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Use braces when letters follow the variable name. Without them, Bash looks for a different variable:
$ echo "Hello ${name}s"
Hello Ucartzs
$ echo "Hello $names."
Hello .
An unset variable prints as nothing, without an error. To show a fallback instead: echo "${UNSET_VAR:-default value}" printed default value.
Double quotes, single quotes and no quotes
$ echo "Hello $name" Hello Ucartz $ echo 'Hello $name' Hello $name $ echo "Cost: \$5" Cost: $5
Double quotes replace variables; single quotes print everything exactly as typed. Without quotes, Bash also splits the value on spaces and expands wildcards:
$ files="a b" $ echo $files a b $ echo "$files" a b $ echo * app.log index.html style.css $ echo "*" *
So put variables in double quotes unless you have a reason not to.
Special $ variables
$?: exit status of the last command.false; echo $?printed1,true; echo $?printed0.$$: process ID of the current shell.$0: name of the script, for example/echo.shin our test.$1,$2,$#,$@: script arguments, their number and all of them. Afterset -- one two three,echo "args: $# first: $1 all: $@"printedargs: 3 first: one all: one two three.
Command output and arithmetic
$ echo "Today is $(date +%A)" Today is Tuesday $ echo "2 + 3 = $((2 + 3))" 2 + 3 = 5
$( ) runs a command and inserts its output; $(( )) does whole-number arithmetic.
Options: -n and -e
$ echo -n "no newline"; echo "|" no newline| $ echo "line1\nline2" line1\nline2 $ echo -e "line1\nline2" line1 line2 $ echo -e "col1\tcol2" col1 col2
-n leaves out the final new line; -e turns on escapes such as \n (new line) and \t (tab).
Scripts that start with #!/bin/sh behave differently on Debian and Ubuntu, where /bin/sh is dash. There, echo "line1\nline2" printed two lines, and echo -e "x\ty" printed -e x y. Use #!/bin/bash or printf if the output must be the same everywhere.
Write to a file
echo "hello" > /tmp/out.txt # replace the file echo "again" >> /tmp/out.txt # add a line at the end
sudo echo "text" > /etc/file fails with -bash: /etc/file: Permission denied, because your own shell opens the file, not sudo. Use tee instead:
echo "nameserver 1.1.1.1" | sudo tee -a /etc/test.conf
When to use printf instead
echo can’t print a value that looks like one of its options: echo "-n" printed nothing at all. printf prints any value safely and gives you control over the format:
$ printf '%s\n' "-n" -n
In Bash, echo is a shell builtin (type echo says echo is a shell builtin). There is also a separate program, /bin/echo, from GNU coreutils.
Related: set environment variables, set $PATH permanently, a script with variables and redirect standard error.
Official documentation: Bash reference manual, builtin commands.