Here-doc: multi-line stdin
When you need to feed a command multi-line text without creating a temp file:
cat <<EOF > /etc/myapp/config.ini
[server]
host = localhost
port = 8080
user = ${USER}EOF
Everything between <<EOF and the closing EOF goes to the command's stdin
(here that is cat, which writes to a file through >). EOF is just a
marker; you can use any word (END, DONE, __SCRIPT__).
Variable expansion: with quotes or without
By default ${VAR} and $(...) expand inside a here-doc:
cat <<EOF
Hello, ${USER}!Today is $(date +%F)
EOF
▸Hello, student!
▸Today is 2026-04-29
If you want literal text with no expansion, quote the marker:
cat <<'EOF' > script.template
Hello, ${USER}! # ← does NOT expand, stays as ${USER}$HOME too # ← does NOT expand
EOF
This matters when you generate scripts, templates, or Dockerfile fragments
where $VAR must stay as literal text.
Stripping leading tabs: <<-
Inside indented blocks (if, function) a here-doc looks ugly, because the
indentation ends up in the text. The fix is <<- (minus): bash strips
leading tabs (not spaces):
if [[ -d /etc ]]; then
cat <<-EOF
this message
has leading tabs
that bash will strip
EOF
fi
Tabs only. If your editor inserts spaces, it will not work.
Here-string: <<< for a single line
The single-line counterpart:
grep apple <<< "i like apple pie"
▸grep reads "i like apple pie" from stdin as if from a file
▸same as: echo "i like..." | grep apple, but with NO pipe and no echo subprocess
Handy for bc, jq, any command that wants stdin data:
bc <<< "2 + 2" # 4
jq '.name' <<< '{"name":"alice"}' # "alice"Common mistakes
- A marker with trailing spaces: bash will not close the here-doc:
bash
cat <<EOF
text
EOF <-- space after EOF! will not close
<<-with spaces instead of tabs: the stripping will not happen.- Cross-platform:
<<<exists in bash and zsh, not in/bin/sh. For POSIX compatibility, useprintf '...' | cmd.