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.
Theprintf
utility can be used portably to emulate any of the traditional behaviors of theecho
utility [...]
Related Topics
Install Marklogic Centos Virtualbox Vm
How to Detect Usb Drive Insertion in Linux
How to Wrap Lines Within Columns in Linux
Embedding the Password in the Bash Script
Turning Multiple Lines into One Comma Separated Line
View a Log File in Linux Dynamically
Logo Programming Language Implementations
Equivalent of Ctrl C in Command to Cancel a Program
Why I Cannot Override Search Path of Dynamic Libraries with Ld_Library_Path
How to Use Sed to Remove the Last N Lines of a File
Using Ld_Preload Mixed 64Bit/32Bit Environment in Linux
Undefined Reference to 'Dlopen'
(Master) at End of Terminal Prompt
Compile/Run Assembler in Linux