When working with multiline variables in a
Bourne or
Korn shell there are certain subtleties to using quotes which - if used careless - can give quite different results.
A
multiline variable is a variable which contains
two or more lines of text.
I will discuss for a given multiline variable $T the differences between
- echo $T
- echo "$T"
- printf $T
- printf "$T"
- printf "%s" $T
- printf "%s" "$T"
If you know which of these commands show the same result you can skip this page.
Example: assume your /etc/hosts looks like this
#
# Internet host table
#
127.0.0.1 localhost
10.6.102.3 comp-nis
10.6.129.146 foo.Bar.COM loghost
192.168.127.1 foo.Bar.COM-ce1 # DO NOT MODIFY
and your variable $T should contain all lines with the string 'host' in it ie. lines 2, 4 and 6.
% T=`grep host /etc/hosts`
echo $T displays all 3 lines in one line
% echo $T
# Internet host table 127.0.0.1 localhost 10.6.129.146 foo.Bar.COM loghost
echo "$T" displays all 3 lines as 3 lines ie. truly showing the results of the grep command
% echo "$T"
# Internet host table
127.0.0.1 localhost
10.6.129.146 foo.Bar.COM loghost
Since the use of
echo is discouraged these days one needs to look at
printf.
printf $T dislays only the first word in $T which happens to be just
# in our case.
% printf $T
#%
printf "$T" shows all 3 lines but
without the final newline
% printf "$T"
# Internet host table
127.0.0.1 localhost
10.6.129.146 foo.Bar.COM loghost%
printf "%s" $T shows all 3 lines in one line by removing all white space (blanks and newlines) i.e. also without the final newline
% printf "%s" $T
#Internethosttable127.0.0.1localhost10.6.129.146foo.Bar.COMloghost%
printf "%s" "$T" shows all 3 lines but
without the final newline (same output as
printf "$T")
% printf "%s" "$T"
# Internet host table
127.0.0.1 localhost
10.6.129.146 foo.Bar.COM loghost%
So out of all versions only
echo "$T" did what one would expect and could be replaced by
printf "$T\n" or
printf "%s\n" "$T" ie. printf with a final newline.
The difference becomes important when you feed the contents of a variable to some command like
U=`echo $T | some_cmd ...`
Assume you want to replace 'host' by 'HOST' in our example.
U=`echo "$T" | sed 's/host/HOST/'` is the right solution: 3 changed lines in $U
% echo "$U"
# Internet HOST table
127.0.0.1 localHOST
10.6.129.146 foo.Bar.COM logHOST
U=`echo $T | sed 's/host/HOST/'` will produce a one line output and only the first occurance of 'host' will be replaced
% echo "$U"
# Internet HOST table 127.0.0.1 localhost 10.6.129.146 foo.Bar.COM loghost
Sometimes though transferring a multiline output into a single line is what is needed so the difference in behaviour can be used to one's advantage.
Note that in
csh there doesn't seem to be a way to preserve the multiline nature in a variable (at least I don't know of any).