Here Documents / Here Strings
| Since: | << ヒアドキュメント | POSIX(sh互換) |
|---|---|---|
| <<< ヒアストリング | Bash(bash拡張) |
In shell scripts, the syntax for embedding multi-line text directly in a script and passing it as standard input to a command is called a "here document." It is written in the form <<EOF ... EOF, allowing you to pass long strings to commands without preparing a separate file. Several variations exist for different use cases, including <<- for stripping leading indentation, and the "here string" (<<<) for passing a single string as standard input.
Basic Here Document (<<)
Writing <<WORD reads everything from the next line until a line containing only WORD appears, and passes that content as standard input. The delimiter word is conventionally EOF, but any string can be used. No whitespace is allowed before or after the delimiter word on its own line.
| Syntax | Description |
|---|---|
command <<EOF | Passes everything up to the next EOF line as standard input to command. Variable expansion and command substitution are active. |
command <<WORD | Any delimiter word other than EOF can be used. The delimiter can be any string as long as it is unique within the script. |
| Delimiter on its own line | Closes the here document by placing the delimiter alone at the start of a line. No leading or trailing whitespace or tabs are allowed (except with <<-). |
Stripping Indentation (<<-)
Using <<-WORD strips leading tab characters from the here document body and the delimiter line. This lets you keep the script visually indented while preserving clean output. Note that only tabs are stripped — spaces are not removed, so you must use tabs for indentation.
| Syntax | Description |
|---|---|
command <<-EOF | Strips leading tabs from the body and delimiter line before passing the content to command. |
| Leading spaces are not stripped | Only tab characters are removed. If you indent with spaces, they will remain in the output. |
Suppressing Variable Expansion (<<'EOF')
Surrounding the delimiter word with single quotes (<<'EOF') or escaping it with a backslash (<<\EOF) suppresses all variable expansion, command substitution, and backslash interpretation within the here document body. This is useful when you want to output another script or template file literally.
| Syntax | Variable Expansion | Description |
|---|---|---|
<<EOF | Active | ${variable} and $(command) are expanded. |
<<'EOF' | Inactive | The body is output literally without any expansion. |
<<\EOF | Inactive | Has the same effect as <<'EOF'. |
Here String (<<<)
<<< (here string) is a bash/zsh-specific syntax for passing a single string as standard input. It is less verbose than a here document and is handy when you want to feed a one-line string to a command instead of using a pipe. It is not available in sh.
| Syntax | Description |
|---|---|
command <<< "string" | Passes the double-quoted string as standard input to command. Variable expansion is active. |
command <<< 'string' | Passes the single-quoted string literally. Variable expansion is inactive. |
command <<< $variable | Passes the value of a variable as standard input. A newline is automatically appended at the end. |
Sample Code
jjk_heredoc_basic.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates basic here document behavior
# using Jujutsu Kaisen characters
# -----------------------------------------------
# -----------------------------------------------
# 1. Basic here document (with variable expansion)
# -----------------------------------------------
# Store the sorcerer's name in variables
SORCERER="Itadori Yuji"
GRADE="Grade 1"
# Pass a here document to cat to print multiple lines
# ${SORCERER} and ${GRADE} are expanded inside the here document
cat <<EOF
=== Sorcerer Profile ===
Name: ${SORCERER}
Grade: ${GRADE}
School: Tokyo Jujutsu High
EOF
echo ""
# -----------------------------------------------
# 2. Suppress variable expansion (<<'EOF')
# -----------------------------------------------
# Quoting the delimiter outputs ${SORCERER} as a literal string
# Useful when generating shell script templates
cat <<'EOF'
=== Template (no variable expansion) ===
Name: ${SORCERER}
Grade: ${GRADE}
School: ${SCHOOL}
EOF
echo ""
# -----------------------------------------------
# 3. Passing to tee instead of cat
# Here we write the output to a file with tee
# -----------------------------------------------
OUTPUT_FILE="gojo_profile.txt"
# Write Gojo Satoru's profile to a file
tee "${OUTPUT_FILE}" <<EOF
Name: Gojo Satoru
Grade: Special Grade
Technique: Limitless (Infinity)
EOF
echo "Written to gojo_profile.txt."
cat "${OUTPUT_FILE}"
# Clean up
rm -f "${OUTPUT_FILE}"
$ chmod +x jjk_heredoc_basic.sh
$ ./jjk_heredoc_basic.sh
=== Sorcerer Profile ===
Name: Itadori Yuji
Grade: Grade 1
School: Tokyo Jujutsu High
=== Template (no variable expansion) ===
Name: ${SORCERER}
Grade: ${GRADE}
School: ${SCHOOL}
Written to gojo_profile.txt.
Name: Gojo Satoru
Grade: Special Grade
Technique: Limitless (Infinity)
jjk_heredoc_indent.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates indentation stripping with <<-
# Note: this script must use tab indentation
# -----------------------------------------------
report_sorcerer() {
local name="$1"
local grade="$2"
local technique="$3"
# <<- strips leading tabs from the body and delimiter line
# This lets you write a here document with consistent indentation inside a function
cat <<-EOF
=== Sorcerer Report ===
Name : ${name}
Grade : ${grade}
Technique: ${technique}
EOF
# ↑ The EOF line also has a leading tab, but <<- strips it
echo ""
}
# Print reports for three Jujutsu Kaisen characters
report_sorcerer "Fushiguro Megumi" "Grade 1" "Ten Shadows Technique"
report_sorcerer "Kugisaki Nobara" "Grade 1" "Straw Doll Technique"
report_sorcerer "Nanami Kento" "Grade 1" "Ratio Technique"
$ chmod +x jjk_heredoc_indent.sh $ ./jjk_heredoc_indent.sh === Sorcerer Report === Name : Fushiguro Megumi Grade : Grade 1 Technique: Ten Shadows Technique === Sorcerer Report === Name : Kugisaki Nobara Grade : Grade 1 Technique: Straw Doll Technique === Sorcerer Report === Name : Nanami Kento Grade : Grade 1 Technique: Ratio Technique
jjk_herestring.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates <<< (here string)
# This is a bash/zsh-specific syntax (not available in sh)
# -----------------------------------------------
# -----------------------------------------------
# 1. Pass a string directly to the read command
# -----------------------------------------------
# Split a "name grade" string with read using a here string
read -r name grade <<< "Gojo Satoru Special-Grade"
echo "Name: ${name} / Grade: ${grade}"
# → Name: Gojo Satoru / Grade: Special-Grade
echo ""
# -----------------------------------------------
# 2. Pass a variable's value as standard input
# -----------------------------------------------
TARGET="Getou Suguru"
# Pass a string to grep via here string for pattern matching
# More concise than using echo with a pipe
if grep -q "Getou" <<< "${TARGET}"; then
echo "${TARGET} is a member of the Getou faction."
fi
echo ""
# -----------------------------------------------
# 3. Pass a math expression to bc via here string
# -----------------------------------------------
# Calculate Gojo's technique power level (fictional values)
LEVEL=9999
MULTIPLIER=2
result=$(bc <<< "${LEVEL} * ${MULTIPLIER}")
echo "Limitless max output: ${result}"
# → Limitless max output: 19998
echo ""
# -----------------------------------------------
# 4. Comparison with pipe (both produce the same result)
# -----------------------------------------------
SORCERER_INFO="Itadori Yuji / Black Flash / Divergent Fist"
# Using a here string
word_count_heredoc=$(wc -w <<< "${SORCERER_INFO}")
# Using echo with a pipe
word_count_pipe=$(echo "${SORCERER_INFO}" | wc -w)
echo "Here string: ${word_count_heredoc} words"
echo "Pipe : ${word_count_pipe} words"
# Both produce the same result
$ chmod +x jjk_herestring.sh $ ./jjk_herestring.sh Name: Gojo / Grade: Satoru (output varies by how read splits the string) Getou Suguru is a member of the Getou faction. Limitless max output: 19998 Here string: 6 words Pipe : 6 words
jjk_heredoc_script_gen.sh (Applied: generating another script)
#!/bin/bash # ----------------------------------------------- # Demonstrates using <<'EOF' (no variable expansion) # to dynamically generate another shell script # ----------------------------------------------- OUTPUT_SCRIPT="jjk_generated.sh" # ----------------------------------------------- # Header section: expand variables when writing (< $ chmod +x jjk_heredoc_script_gen.sh $ ./jjk_heredoc_script_gen.sh Generated script: jjk_generated.sh #!/bin/bash # Auto-generated script # Generated at: 2026-03-27 10:00:00 # Generated by: jjk_heredoc_script_gen.sh === Special Grade Sorcerers === - Gojo Satoru - Getou Suguru - Yuki Tsukumo - Hiromi Higuruma - Tengen
Choosing Between << / <<- / <<< / <<'EOF'
| Syntax | Variable Expansion | Strip Leading Tabs | Typical Use Case |
|---|---|---|---|
<<EOF | Active | No | Use when you want to pass multiple lines while expanding variables. |
<<-EOF | Active | Tabs only | Use inside functions or other indented blocks where you want aligned indentation. |
<<'EOF' | Inactive | No | Use when you want to pass content literally, such as for templates or script generation. |
<<< "string" | Active | — | Use when you want to pass a single line of text instead of a pipe (bash/zsh only). |
Common Pitfalls
| Pitfall | Cause and Fix |
|---|---|
| Delimiter is not recognized | The delimiter line has leading or trailing whitespace or tabs. With <<, place the delimiter alone at the start of the line. With <<-, leading tabs are stripped, but spaces are not. |
Indentation remains with <<- | You are using spaces for indentation. <<- only strips tab characters, so space-indented lines are left as-is. |
<<< does not work | You are running the script with sh. Here strings are a bash/zsh-specific feature. Change the shebang to #!/bin/bash or run the script with bash script.sh. |
$ inside the here document is expanded unexpectedly | The delimiter word is not quoted. Use <<'EOF' or <<\EOF to suppress expansion. |
Wrong order when writing to a file with > | Write it as cat > file <<EOF. While cat <<EOF > file also works, the former is more conventional and easier to read. |
Summary
The here document (<<) in shell scripts is a syntax for embedding multi-line text directly in a script and passing it as standard input. The basic form is <<EOF ... EOF, and variable expansion and command substitution are active by default. Using <<'EOF', which surrounds the delimiter with single quotes, disables expansion and is useful for templates and generating other scripts. <<-EOF strips leading tabs from the body and delimiter line, allowing you to write a here document with consistent indentation inside a function (note that spaces are not stripped). <<< (here string) is bash/zsh-specific and provides a more concise alternative to a pipe when you only need to pass a single line of text as standard input. For the basics of redirection, see also Redirect.
If you find any errors or copyright issues, please contact us.