Quoting, expanding variables and such
Here-document (<<) allows you to pass quotes without escaping them. It also lets you decide if certain expansions should occur in a way that doesn't interfere with quotes you need to pass.
Try:
var="12 3"
cat <<EOF
'$var"
EOF
The output is
'12 3"
To get this with echo you need one of the following:
echo "'$var"'"'
echo "'$var\""
or something similarly ugly. By looking at these commands it's hard to tell what the output should be, while the here-document it's pretty clear.
What if you don't want the variable to be expanded? You can do this:
cat <<'EOF'
'$var"
EOF
The output is literally
'$var"
Again the here-document is clear. Compare to these commands:
echo "'\$var\""
echo "'"'$var"'
In some cases you still need to escape things. e.g.
var="12 3"
cat <<EOF
We need '\$var" to be expanded and look like this: '$var"
EOF
to get
We need '$var" to be expanded and look like this: '12 3"
But with echo it's even worse:
echo "We need '\$var\" to be expanded and look like this: '$var\""
echo 'We need '"'"'$var" to be expanded and look like this: '"'$var"'"'
Could you easily predict the exact output of the last echo? Now imagine you need to add a variable to be expanded between the literal look and like. Is look like in single-quotes or in double-quotes in the already existing command?
- if in single-quotes then the snippet should become
look '"$foo"' like
- if in double-quotes then the snippet should become
look $foo like
In general there can be quotes within quotes and only the outer ones matter, so to tell which solution to use you need to parse the whole string from the beginning (or from the end), apply some heuristics or just go with trial and error.
Back to here-document. Thanks to it being clear it's easy to make changes right. echo with quoting frenzy can be so much harder to maintain.
Process flow
A here-document is processed by the shell running the script. Just after the shell sees
cat >"$file" <<EOF
it knows all the required redirections. It can read the following lines one by one and pass them to cat on the fly. I'm not saying it always does, I'm saying it's technically possible for arbitrarily long here-document.
On the other hand after the shell sees
echo "command1 $var_this_routine
it needs to read the whole multi-line string to discover the redirection at the end:
" >"$file"
Even if we started with
>"$file" echo "command1 $var_this_routine
the shell cannot be sure there are no more redirections until it gets beyond the closing ". To know what to do with the string the shell must read and memorize the whole of it.
And then it needs to pass the string to echo (or printf). In many shells echo is a builtin and it may (or may not) support very long arguments. But echo is not required to be a shell builtin, it may be a separate executable only. In such case the shell needs to pass the string to the executable and there are some limits.
So probably if anything is going to fail then it will be the echo method rather than here-document.