100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Bash

Here-Documents and Here-Strings

Learn how to feed multi-line literal text into commands using heredocs (<<) and here-strings (<<<), including quoting rules and indentation control.

I/O & Text ProcessingIntermediate8 min readJul 10, 2026
Analogies

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.

bash
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
fi

Controlling 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.

bash
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 3

command | 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 <<DELIMITER feeds 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 read runs 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

Was this page helpful?

Topics covered

#Bash#AdvancedBashScriptingStudyNotes#DevOps#HereDocumentsAndHereStrings#Here#Documents#Strings#Document#StudyNotes#SkillVeris