Linux Basic — Here-Documents
Here-Documents (<<EOF)
A here-document feeds a block of literal text as standard input to a command. It replaces fragile echo -e "line1\nline2" chains and is the canonical way to embed SQL, config templates, or multi-line emails inside a script.
Basic Syntax
cat <<EOF
Hello, $USER
Today is $(date +%F).
EOF
The delimiter (EOF) is your choice — it just has to appear unindented on a line by itself to end the heredoc. Variables ($USER) and command substitution ($(date)) are expanded by default.
Disable Expansion: Quote the Delimiter
cat <<'EOF'
Literal $USER, no expansion.
Backticks `like this` stay literal too.
EOF
Quoting the opening delimiter ('EOF' or "EOF") treats the body as raw text. Use this for scripts within scripts, AWK programs, or anything containing $ you don’t want expanded.
Strip Leading Tabs: <<-
<<-EOF strips leading tab characters (not spaces) from each line — letting you indent the body to match surrounding code:
if true; then
cat <<-EOF
this line has leading tabs
they will be stripped
EOF
fi
Only tabs are stripped. Mixing tabs and spaces silently breaks this.
Heredocs to Commands Other Than cat
Anything that reads stdin works:
# Send mail
mail -s "Report" ops@example.com <<EOF
Run completed at $(date).
EOF
# Pipe SQL to psql
psql -d mydb <<SQL
SELECT count(*) FROM users WHERE active = true;
SQL
# Build a config file
sudo tee /etc/myapp.conf >/dev/null <<EOF
listen_port = 8080
log_level = info
EOF
Capture a Heredoc into a Variable
template=$(cat <<EOF
host: $HOSTNAME
user: $USER
EOF
)
echo "$template"
Common Pitfalls
| Pitfall | Fix |
|---|---|
Closing EOF is indented with spaces |
Must be flush-left (or use <<- with tabs only) |
Trailing whitespace after opening <<EOF |
Bash treats the literal delimiter strictly — clean line endings |
| Variable expansion happens when you don’t want it | Quote the delimiter: <<'EOF' |
| Heredoc inside a pipeline runs in a subshell | Variables set inside aren’t visible after |
Quick Reference
| Form | Expansion | Indent stripping |
|---|---|---|
<<EOF |
yes | none |
<<'EOF' |
no | none |
<<-EOF |
yes | leading tabs |
<<-'EOF' |
no | leading tabs |
Next → Here-Strings