Difference Between Printf and Echo in Bash

Difference between printf and echo in Bash

First sentence of entry for echo in the bash man page (emphasis mine):

Output the args, separated by spaces, followed by a newline.

First sentence of the man page entry for printf:

Write the formatted arguments to the standard output under the control of the format.

printf only prints what appears in the format; it does not append an implied newline.

There may be other difference between echo "foo" and printf "foo", depending on what exactly foo is. The POSIX specification gives implementations broad discretion in how it implements echo, probably to avoid choosing from among the diverse historical implementations as the standard. Use printf when you rely on the precise output.

Difference between echo and printf in Bash

Using echo $line automatically includes a newline - which you can suppress with the -n option (sometimes - see below). So this doesn't work:

echo $line | md5sum | awk '{print $1}' >> md5File.txt

But on bash this does:

echo -n $line | md5sum | awk '{print $1}' >> md5File.txt

But Not all versions of echo have an -n option. The echo documentation says:

If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined.
... On XSI-conformant systems, if the first operand is -n, it shall be treated as a string, not an option.

Another alternative is using bash's printf command. The printf documentation says:

The printf utility was added to provide functionality that has historically been provided by echo. However, due to irreconcilable differences in the various versions of echo extant, ...

So printf is the reliably portable way to go. Here is a related answer with more details: https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo

But using printf is dangerous if you don't specify a format string, so even though this seems to work:

printf $line | md5sum | awk '{print $1}' >> md5File.txt

It will fail spectacularly when $line contains a percent sign or a backslash. The first argument to printf is the format string and is treated specially. If the format string is invalid then printf produces an error to stderr and an empty string to stdout, which gives the wrong answer. So instead you need:

printf "%s" "$line" | md5sum | awk '{print $1}' >> md5File.txt

The %s tells printf to expect one more string parameter (which just happens to be $line) and you get the right output.

Fun fact: if you did want printf to add a trailing newline (you don't in this case) then you would

printf "%s\n" "$line" | md5sum | awk '{print $1}' >> md5File.txt

What is more portable? echo -e or using printf?

printf is more portable. It should always be preferred over echo -e. If targeting bash/zsh/ksh specifically, echo $'...' is also ok. If targeting zsh or ksh specifically, print is ok.

  • http://cfajohnson.com/shell/cus-faq.html#Q0b
  • http://www.in-ulm.de/~mascheck/various/echo+printf/
  • http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16

POSIX (last link) also discusses echo -n problems, which should also be avoided. Basically, never use options to echo, and for portability, use printf.)

What is the difference between `$( ... )` and `( ... )`?

Merely running commands, in a subshell or not, does not involve any interaction with the shell itself after it executes those commands.

$ echo echo poo
echo poo

By contrast, a command substitution is evaluated by the shell after it finishes:

$ $(echo echo poo)
poo

$ var=$(echo echo poo)

$ echo "$var"
echo poo

$ $(echo "$var") # expands to the first line (but is unnecessarily redundant)
poo

$ $var # more succinct version of the previous line
poo

Of course, if you redirect the output of the command substitution, the shell ends up evaluating an empty string.

The . command (or, in Bash and some other non-POSIX shells, its synonym source) evaluates a sequence of commands in a file. This is in some sense vaguely similar to a command substitution, but the latter lets you capture and manipulate the result of the evaluation (and in some sense the whole purpose of the shell is to evaluate expressions).

A command substitution can really be used to evaluate an expression anywhere, whereas . or a subshell can only be used where the shell accepts a command. Look at these gymnastics:

$ $(echo e)$(echo c)$(echo h)$(echo o) "poo"
poo

$ echo p$(printf x | wc -l | tr -d ' ' | tr '1' 'o')o
poo

$ ech$(echo o poo)
poo

Like you discovered, a subshell can be useful when you want a group of commands to share some file discriptors;

( printf '%s\n' 'Subject: hello' \
'MIME-version: 1.0' \
'Content-type: application/octet-stream' \
'Content-transfer-encoding: base64' \
''
base64 binaryfile ) |
sendmail -oi you@example.net

or if you want to limit the scope of some environment changes;

for subdir in */; do
( cd "$subdir"
condiments=$(cat spice.txt)
export condiments
make -s dinner )
# back in parent dir
# $condiments is back to its old value
# probably unset, and not exported
done

What is the difference between echo and echo -n ?

When you do echo "password" | md5, echo adds a newline to the string to be hashed, i.e. password\n. When you add the -n switch, it doesn't, so only the characters password are hashed.

Better to use printf, which does what you tell it to without needing any switches:

printf 'password' | md5

For cases where 'password' isn't just a literal string, you should use a format specifier instead:

printf '%s' "$pass" | md5

This means that escape characters within the password (e.g. \n, \t) aren't interpreted by printf and are printed literally.

echo output different answer by sh and bash

echo is not very portable (even Bash's echo may behave differently on different OSes which may use different default options when compiling Bash). You can use printf. According to posix:

It is not possible to use echo portably across all POSIX systems unless both -n (as the first argument) and escape sequences are omitted.
The printf utility can be used portably to emulate any of the traditional behaviors of the echo utility [...]



Related Topics



Leave a reply



Submit