Bash Heredoc: Complete Guide with Examples

By 

Updated on

6 min read

Bash Heredoc

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:

txt
[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 EOF or END are 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.
  • 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
sh
cat << EOF
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF

The output shows the expanded variable and command substitution:

output
The current working directory is: /home/linuxize
You are logged in as: linuxize

Quoted Delimiter (Literal Mode)

Quoting the delimiter with single or double quotes disables all shell expansions:

sh
cat << 'EOF'
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF
output
The 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.

sh
#!/bin/bash

generate_page() {
	cat <<-EOF
	<html>
	<head>
		<title>$1</title>
	</head>
	<body>
		<h1>$1</h1>
	</body>
	</html>
	EOF
}

generate_page "My Page"
output
<html>
<head>
	<title>My Page</title>
</head>
<body>
	<h1>My Page</h1>
</body>
</html>
Warning
The <<- 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:

sh
cat << EOF > /tmp/myfile.txt
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF

If 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:

sh
sudo tee /etc/myconfig.conf << EOF
setting1=value1
setting2=value2
EOF

Piping 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:

sh
cat <<'EOF' | sed 's/l/e/g'
Hello
World
EOF
output
Heeeo
Wored

To write the piped data to a file:

sh
cat <<'EOF' | sed 's/l/e/g' > file.txt
Hello
World
EOF

Using 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:

sh
ssh -T user@host.com << EOF
echo "Local working directory: $PWD"
echo "Remote working directory: \$PWD"
EOF
output
Local working directory: /home/linuxize
Remote working directory: /home/user

The 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:

sh
ssh -T user@host.com << 'EOF'
echo "Remote working directory: $PWD"
echo "Remote user: $(whoami)"
EOF

Best 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:

sh
command <<< "string"

For example, to pass a string to grep:

sh
grep "linux" <<< "I love linux and bash"
output
I love linux and bash

Herestrings are useful when you need to pass a variable or short string to a command without using echo and a pipe:

sh
# Using herestring
tr '[:lower:]' '[:upper:]' <<< "hello world"

# Equivalent using echo and pipe
echo "hello world" | tr '[:lower:]' '[:upper:]'

Both commands output:

output
HELLO WORLD

Practical Examples

Writing a Configuration File

sh
cat << EOF > /tmp/nginx.conf
server {
    listen 80;
    server_name $DOMAIN;
    root /var/www/$DOMAIN/html;

    location / {
        try_files \$uri \$uri/ =404;
    }
}
EOF

Note that $DOMAIN is expanded locally, while $uri is escaped to be written literally.

Running SQL Queries

sh
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)
);
EOF

Generating JSON

sh
cat << EOF > data.json
{
    "name": "$USER",
    "home": "$HOME",
    "shell": "$SHELL"
}
EOF

Common Mistakes

Spaces Before Closing Delimiter

The closing delimiter must be at the beginning of a line with no leading whitespace:

sh
# Wrong - spaces before EOF
cat << EOF
Hello World
  EOF

# Correct
cat << EOF
Hello World
EOF

Using Spaces Instead of Tabs with <<-

The <<- operator only strips tabs, not spaces:

sh
# 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
fi

Unintended Variable Expansion

Variables in heredocs are expanded by default, which can cause unexpected results:

sh
# This will fail or produce unexpected output
cat << EOF
The price is $5.00
EOF

Fix by escaping the dollar sign or quoting the delimiter:

sh
# 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
EOF

Quick Reference

SyntaxDescription
<< EOFHeredoc with variable expansion
<< 'EOF'Heredoc without variable expansion (literal)
<< "EOF"Same as quoted single quotes (literal)
<<- EOFHeredoc 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

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