What a Here-Document Is
A here-document, written <<DELIMITER, lets you embed a multi-line block of literal text directly inside a script and feed it to a command's stdin, avoiding the need for a separate text file. Bash reads every line until it finds a line containing only the chosen delimiter (commonly EOF), and by default it performs the same parameter expansion, command substitution, and arithmetic expansion inside the block that double-quoted strings receive, so variables like $USER are replaced with their values.
Cricket analogy: A team manager handing the umpire a pre-written team sheet listing all eleven players at once, rather than announcing each name one at a time, mirrors a heredoc feeding a whole block of text to a command's stdin in one go.
USER_NAME="Asha"
cat <<EOF
Hello, $USER_NAME!
Today's date is $(date +%F).
Math check: $((2 + 2)) equals four.
EOF
# Quote the delimiter to disable expansion (literal output)
cat <<'EOF'
This $USER_NAME and $(date) will NOT be expanded.
EOF
# Indented heredoc body with <<- (strips LEADING TABS only, not spaces)
if true; then
cat <<-EOF
This line's leading tabs are stripped.
EOF
fiControlling Expansion and Indentation
Quoting the delimiter, as in <<'EOF' or <<"EOF", disables all expansion inside the heredoc body, so it is treated as pure literal text, which is essential when embedding another script's source or literal dollar signs and backticks. The <<- variant strips leading tab characters (not spaces) from each line and from the closing delimiter line, which lets you indent a heredoc to match the surrounding code's indentation level for readability without those tabs ending up in the output.
Cricket analogy: A translator who reads out a foreign captain's post-match quote word for word without paraphrasing, rather than interpreting it, mirrors a quoted heredoc delimiter preserving text literally without expansion.
<<- only strips leading TAB characters, never spaces, from each line of the heredoc body and its terminating delimiter. If your editor indents with spaces, <<- will not remove them and the closing delimiter line may fail to match, leaving the heredoc unterminated.
Here-Strings: <<<
A here-string, written command <<< "$variable", feeds a single string (plus a trailing newline that bash appends automatically) to a command's stdin without the multi-line delimiter ceremony of a heredoc, making it the concise choice when you already have the content in a variable. It is especially useful with read and while read loops, since piping into while read runs the loop in a subshell (losing variable changes after the loop), whereas while read line <<< "$data" keeps the loop in the current shell.
Cricket analogy: Handing the umpire a single slip of paper with just today's toss decision, rather than a full team sheet, mirrors a here-string delivering one compact piece of input instead of a multi-line heredoc block.
data="line one\nline two\nline three"
# while read with heredoc-style pipe runs in a SUBSHELL: count is lost after
count=0
printf '%s\n' "a" "b" "c" | while read -r x; do ((count++)); done
echo "After pipe loop: count=$count" # prints 0
# while read with a here-string keeps the loop in the CURRENT shell
count=0
while read -r x; do ((count++)); done <<< "$(printf '%s\n' a b c)"
echo "After here-string loop: count=$count" # prints 3command | while read ... runs the while loop in a subshell in bash, so any variables modified inside the loop (like a running counter) revert to their prior values once the loop exits. Use while read ... <<< "$var" or while read ... done < <(command) (process substitution) to keep the loop in the current shell when you need its side effects to persist.
- A heredoc
<<DELIMITERfeeds a multi-line literal block to a command's stdin, ending at a line containing only the delimiter. - Unquoted delimiters allow variable, command, and arithmetic expansion inside the block; quoting the delimiter disables all expansion.
<<-strips only leading tab characters (not spaces) from each line, useful for indenting heredocs to match surrounding code.- A here-string
<<<feeds a single string plus a trailing newline to stdin, ideal when content is already in a variable. command | while readruns the loop in a subshell, so variable changes inside it are lost after the loop ends.while read ... <<< "$var"or< <(command)keeps the while loop in the current shell so its variable changes persist.- Both heredocs and here-strings avoid the need to create a separate temporary file just to supply literal input.
Practice what you learned
1. What terminates a heredoc block started with `<<EOF`?
2. What is the effect of quoting the delimiter, e.g. `<<'EOF'`, on a heredoc's contents?
3. Why does `cat file.txt | while read -r line; do count=$((count+1)); done; echo $count` often print an unexpected value like 0?
4. Which construct correctly avoids the subshell problem when reading from a variable into a while loop?
5. What does `<<-` do differently from a plain `<<` heredoc?
Was this page helpful?
You May Also Like
Advanced Redirection
Master file descriptor manipulation, combined stdout/stderr redirection, process substitution, and safety guards so a script's input and output flow exactly where you intend.
Advanced awk Scripting
Go beyond simple field printing to use awk's associative arrays, user-defined functions, BEGIN/END blocks, and multiple field separators for real text-processing programs.
Advanced sed Scripting
Move past basic search-and-replace to use sed's address ranges, hold space, branching, and in-place editing for multi-line, stateful text transformations.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics