A here-document — heredoc — embeds a multi-line text block inside a script and feeds it to a command's stdin. It is how scripts write config files, feed SQL to a client, and print usage text without a forest of echo statements.

The basic form #

Write a config file from a script
cat > /etc/aospix/agent.conf <<EOF
host = aospix.com
port = 443
token = $TOKEN
EOF

Everything between <<EOF and the closing EOF goes to cat's stdin — the shell reads until the delimiter appears alone on a line. The redirect works like any other: > creates, >> appends, | pipes onward.

Quoting the delimiter #

By default the body is expanded: variables fill in, commands run. Quote the delimiter and the body becomes literal — the difference between a template and a copy:

Unquoted expands, quoted does not
$ name=world
$ cat <<EOF
hello $name
EOF
hello world
$ cat <<'EOF'
hello $name
EOF
hello $name

The quoted form is the right one for feeding interpreters — SQL, awk programs, scripts you are generating:

Hand SQL to a client, no shell expansion
psql "$DB" <<'SQL'
SELECT count(*) FROM subscribers
WHERE created_at > now() - interval '7 days';
SQL

The forms #

FormBehaviour
<<EOFExpand variables and commands in the body
<<'EOF'Fully literal body
<<-EOFStrip leading tabs — indented scripts
<<<wordHere-string: one word as stdin

<<- only strips tabs, which clashes with space-indented scripts — either indent the body with tabs or accept column zero for the closer. The here-string <<< is the everyday shortcut for "run this command on one line of input":

Feed a single string
$ grep -F "$token" <<< "$secrets_file_contents"
$ bc <<< "2^16"

In practice #

Heredocs shine for templated config with a couple of variables — write the file atomically, then move it into place:

Generate, verify, then install a config
tmp=$(mktemp)
cat > "$tmp" <<EOF
server {
  listen 443 ssl;
  server_name ${domain};
}
EOF
nginx -t -c "$tmp" && sudo mv "$tmp" "/etc/nginx/sites/${domain}"

The expansion rules are the quoting rules with a new syntax; combined with trap cleanup for the mktemp file, this is production-safe. The scripting series continues.