Bash Heredoc: Complete Guide with Examples

When writing shell scripts, you may need to pass a multiline block of text or code to an interactive command such as tee
, cat, or sftp
.
In Bash and other shells like Zsh, a Here document (Heredoc) is a type of redirection that allows you to pass multiple lines of input directly to a command.
Heredocs are commonly used for:
- Generating configuration files
- Passing scripts to remote servers via SSH
- Automating interactive commands
- Writing readable multi-line strings in shell scripts
Heredoc Syntax
The basic heredoc syntax looks like this:
[COMMAND] <<[-] 'DELIMITER'
HERE-DOCUMENT
DELIMITER- The first line starts with an optional command followed by the special redirection operator
<<and the delimiting identifier.- You can use any string as a delimiting identifier, though
EOForENDare the most common. - If the delimiting identifier is unquoted, the shell will substitute all variables, commands and special characters before passing the here-document lines to the command.
- Appending a minus sign to the redirection operator
<<-causes all leading tab characters to be ignored. This allows you to use indentation when writing heredocs in shell scripts.
- You can use any string as a delimiting identifier, though
- The here-document block can contain strings, variables, commands and any other type of input.
- The last line ends with the delimiting identifier. White space in front of the delimiter is not allowed.
Heredoc is most often used in combination with the cat command
.
Variable and Command Expansion
Unquoted Delimiter (Default Behavior)
If the delimiter is not quoted, the shell performs:
- Variable expansion (
$VAR) - Command substitution (
$(command)) - Escape sequence processing
cat << EOF
The current working directory is: $PWD
You are logged in as: $(whoami)
EOFThe output shows the expanded variable and command substitution:
The current working directory is: /home/linuxize
You are logged in as: linuxizeQuoted Delimiter (Literal Mode)
Quoting the delimiter with single or double quotes disables all shell expansions:
cat << 'EOF'
The current working directory is: $PWD
You are logged in as: $(whoami)
EOFThe current working directory is: $PWD
You are logged in as: $(whoami)When the delimiter is quoted, no parameter expansion or command substitution is performed by the shell.
This is useful for configuration files, scripts, or regex patterns where you want to prevent accidental variable substitution.
Indented Heredocs with <<-
When using heredocs inside functions, loops, or conditionals, indentation improves readability. The <<- operator strips leading tab characters (not spaces) from each line of the heredoc, including the closing delimiter.
#!/bin/bash
generate_page() {
cat <<-EOF
<html>
<head>
<title>$1</title>
</head>
<body>
<h1>$1</h1>
</body>
</html>
EOF
}
generate_page "My Page"<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>My Page</h1>
</body>
</html><<- operator only strips tabs, not spaces. If your editor converts tabs to spaces, the heredoc will not work as expected.Redirecting Heredoc Output to a File
Instead of displaying the output on the screen, you can redirect it to a file using the > or >> operators:
cat << EOF > /tmp/myfile.txt
The current working directory is: $PWD
You are logged in as: $(whoami)
EOFIf the file doesn’t exist, it will be created. Using > overwrites the file, while >> appends to it.
You can also use tee
to write to a file that requires root permissions:
sudo tee /etc/myconfig.conf << EOF
setting1=value1
setting2=value2
EOFPiping Heredoc Content
Heredoc input can be piped to other commands for further processing.
In the following example, the sed
command replaces all instances of l with e:
cat <<'EOF' | sed 's/l/e/g'
Hello
World
EOFHeeeo
WoredTo write the piped data to a file:
cat <<'EOF' | sed 's/l/e/g' > file.txt
Hello
World
EOFUsing Heredoc with SSH
Heredocs are useful for executing multiple commands on a remote server over SSH .
When using an unquoted delimiter, escape variables that should be evaluated on the remote server:
ssh -T user@host.com << EOF
echo "Local working directory: $PWD"
echo "Remote working directory: \$PWD"
EOFLocal working directory: /home/linuxize
Remote working directory: /home/userThe first $PWD is expanded locally before the heredoc is sent, while \$PWD is escaped and evaluated on the remote server.
To prevent all local expansion, quote the delimiter:
ssh -T user@host.com << 'EOF'
echo "Remote working directory: $PWD"
echo "Remote user: $(whoami)"
EOFBest practices when using heredoc with SSH:
- Use quoted delimiters when all commands should run on the remote server
- Escape variables (
\$VAR) that should be evaluated remotely when using unquoted delimiters - Consider SSH key-based authentication for automation
Herestring
A herestring is a simpler form of heredoc that passes a single line (or a short string) to a command’s standard input. It uses the <<< operator:
command <<< "string"For example, to pass a string to grep:
grep "linux" <<< "I love linux and bash"I love linux and bashHerestrings are useful when you need to pass a variable or short string to a command without using echo and a pipe:
# Using herestring
tr '[:lower:]' '[:upper:]' <<< "hello world"
# Equivalent using echo and pipe
echo "hello world" | tr '[:lower:]' '[:upper:]'Both commands output:
HELLO WORLDPractical Examples
Writing a Configuration File
cat << EOF > /tmp/nginx.conf
server {
listen 80;
server_name $DOMAIN;
root /var/www/$DOMAIN/html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOFNote that $DOMAIN is expanded locally, while $uri is escaped to be written literally.
Running SQL Queries
mysql -u root -p << EOF
CREATE DATABASE myapp;
USE myapp;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
EOFGenerating JSON
cat << EOF > data.json
{
"name": "$USER",
"home": "$HOME",
"shell": "$SHELL"
}
EOFCommon Mistakes
Spaces Before Closing Delimiter
The closing delimiter must be at the beginning of a line with no leading whitespace:
# Wrong - spaces before EOF
cat << EOF
Hello World
EOF
# Correct
cat << EOF
Hello World
EOFUsing Spaces Instead of Tabs with <<-
The <<- operator only strips tabs, not spaces:
# Wrong - using spaces (won't be stripped)
if true; then
cat <<- EOF
Hello # indented with spaces
EOF
fi
# Correct - using tabs
if true; then
cat <<- EOF
Hello # indented with tabs
EOF
fiUnintended Variable Expansion
Variables in heredocs are expanded by default, which can cause unexpected results:
# This will fail or produce unexpected output
cat << EOF
The price is $5.00
EOFFix by escaping the dollar sign or quoting the delimiter:
# Option 1: Escape the dollar sign
cat << EOF
The price is \$5.00
EOF
# Option 2: Quote the delimiter
cat << 'EOF'
The price is $5.00
EOFQuick Reference
| Syntax | Description |
|---|---|
<< EOF | Heredoc with variable expansion |
<< 'EOF' | Heredoc without variable expansion (literal) |
<< "EOF" | Same as quoted single quotes (literal) |
<<- EOF | Heredoc with leading tabs stripped |
<<< "string" | Herestring (single line input) |
Conclusion
Heredocs are a powerful feature in Bash for embedding multi-line input directly in your scripts. They make automation, configuration generation, and remote execution much easier.
Key points to remember:
- Use unquoted delimiters when you need variable expansion
- Use quoted delimiters (
'EOF') when you want literal text - Use
<<-with tabs for indented heredocs - Use herestrings (
<<<) for single-line input
To learn how to run your scripts, check out our guide on how to run a bash script .
If you have any questions or feedback, feel free to leave a comment.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page