How to Use Here Document (HereDoc) in Linux Shell Script

Linux TLDR
Last Updated:
Reading time: 5 minutes

While writing shell script, you might get stuck in the situation where you want to redirect a block of lines from your script to interactive commands like sed, cat, ssh, or ftp.

The purpose of this redirection might vary from situation to situation.

For example, you want to copy the block of lines from the script to a new file, replace the word, or the block of lines are commands that you need to execute in the remote system via ssh.

There is no doubt you can achieve this manually; however, “here document” will make this process way easier than you might think.

Tutorial Details

DescriptionHere Document (HereDoc)
Difficulty LevelLow
Root or Sudo PrivilegesNo
Host System and ArchitectureUbuntu 22.10 (x64)
OS Compatibility Ubuntu, Manjaro, Fedora, etc.
Prerequisites
Internet RequiredNo
Discussed Tools in this Article

What is the Here Document (HereDoc) in Linux?

In Bash and also for other implementations of the shell, like ZSH and Fish, you can use the HereDoc to redirect a multi-line or block of lines from the script as an input to interactive commands.

The syntax for writing the HereDoc looks like the following one:

[COMMAND] <<[-] 'DELIMITER'
  HERE-DOCUMENT
DELIMITER

Let’s break down the above syntax:

  • [COMMAND]: The command is your target interactive command that you will use as an input for redirected multi-line or block of lines from the “HERE-DOCUMENT” location.
  • <<: It is the redirection symbol used to redirect anything from target (Stdout) to destination (Stdin).
  • [-]: If you append this with a redirection symbol, then all the tab spaces will be ignored during redirection, except for the normal space.
  • ‘DELIMITER’: The delimiter is like a container; anything defined between the first and last delimiter will be redirected to the target “[COMMAND]“, and if the delimiter is quoted, it will substitute all variables, commands, and special characters before passing.
  • HERE-DOCUMENT: It is the multi-line or block of lines that contain strings, variables, commands, and any other type of input that will be redirected to the “[COMMAND]“.
  • DELIMITER: The end of the ‘DELIMITER‘ container. White space in front of the delimiter is not allowed.

Note that you can use any string as a delimiter identifier; the most commonly used are EOF, END, Heredoc, Here_document, and CONTAINER.

Here Document (HereDoc) Usage

I will use the following script as an example that contains strings along with environment variables and commands to make things as easy and digestible as possible for beginners.

Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL

Copy the above lines and paste them in the script file with the name “script.sh“, and don’t forget to give executable permission to your script.

$ chmod u+x script.sh

Redirecting the Block of Lines to Cat Command

Now, if you want to redirect this whole section of code to interactive commands like “cat”, then edit the script and define the block of lines between the HereDoc.

cat << CONTAINER
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

If you execute the above script, all the lines between the “CONTAINER” delimiter will be substituted on the output.

$ ./script.sh 
Current user: linuxtldr
Current Directory: /home/linuxtldr
Default Shell: /bin/bash

Redirecting the Block of Lines to Cat Command Without Substituting

Enclose the “CONTAINER” delimiter with single or double quotes to prevent code substitution on the output.

cat << "CONTAINER"
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

When you run the above script, it will prevent parameter expansion and command substitution.

$ ./script.sh 
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL

Redirecting the Block of Lines to Cat Command Without Tabs

If you again edit your file and include space and tabs (to avoid confusion, comments will be removed later).

cat << "CONTAINER"
        Current user: $(whoami)           #Space is used
	Current Directory: $PWD          #Tab is used
Default Shell: $SHELL               
CONTAINER

The above spaces and tabs will also appear in the output.

$ ./script.sh 
        Current user: $(whoami)
	Current Directory: $PWD
Default Shell: $SHELL

If you want to omit the tabs (not spaces), then append the minus (“–“) after the redirection, as shown.

cat <<- "CONTAINER"
        Current user: $(whoami)
	Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

Save and execute the script, and you will find tabs ignored.

$ ./script.sh 
        Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL

Writing the HereDoc Between the For Loop Statement

If you are using the HereDoc between the for loop statement, then use the “<<-” redirection symbol that will allow you to indent your code.

if true; then
	cat <<- EOF
	Line with a tab
	EOF
fi

Output:

$ ./script.sh 
Line with a tab

Redirecting the Block of Lines to a Text File

Instead of printing the output on the screen, you can redirect it to a text or script file by using the “>“, “>>” operators.

Note that if the file does not exist, it will be automatically created in the present directory, and “>” will overwrite the file and “>>” will append the line at the end of the file.

cat << CONTAINER > file.txt
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

Output:

$ ./script.sh 
$ cat file.txt 
Current user: linuxtldr
Current Directory: /home/linuxtldr
Default Shell: /bin/bash

Replacing the String from the Block of Lines

If you want to replace a string from the block of lines and print the output on screen, then pipe the sed command with your delimiter, as shown.

cat <<- CONTAINER | sed 's/Current/Present/'
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

The above command will replace all the “Current” strings with “Present“, as shown.

$ ./script.sh 
Present user: linuxtldr
Present Directory: /home/linuxtldr
Default Shell: /bin/bash

If you want to save the result in a text file, then redirect the output to a text file (ex: “file.txt“).

cat <<- CONTAINER | sed 's/Current/Present/' > file.txt
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

Output:

$ ./script.sh 
$ cat file.txt 
Present user: linuxtldr
Present Directory: /home/linuxtldr
Default Shell: /bin/bash

Writing Multi-line Comments using HereDoc

In Linux, you cannot directly specify comments for a multi-line or block of lines. The only known way is by adding the hash/pound (“#“) sign at the beginning of each line you want to comment on.

But this method is very inconvenient when adding comments to each line and, especially, when removing them.

Also Read: Writing Single-line, Inline, and Multi-line Comments in Linux Shell Script

However, you can use the HereDoc to redirect the output to an undefined variable that will skip the multi-line or block of lines from execution, as shown.

Note: Use this method only for debugging purposes.

<< CONTAINER
Current user: $(whoami)
Current Directory: $PWD
Default Shell: $SHELL
CONTAINER

Run the above script, and you will find all codes between “<<CONTAINER” and “CONTAINER” are skipped.

$ ./script.sh 
$ 

Executing a Series of Commands on the Remote System

If you spend most of the time on a remote system and repetitively execute multiple commands, you can use the HereDoc to execute a block of commands on the remote system at once.

Also Read: What is SSH and How to Install it in Linux?

The following is the script that defines the remote system and a series of commands that need to be executed on the target machine.

ssh -T [email protected] << CONTAINER
echo "Current user:" $(whoami)
echo "Current Directory:" $PWD
echo "Default Shell:" $SHELL
CONTAINER

When you execute the above script, all the specified commands between the “CONTAINER” delimiter will be executed on the “[email protected]” system, as shown.

$ ./script.sh 
Current user: linuxtldr
Current Directory: /home/linuxtldr
Default Shell: /bin/bash

And that was the end of this article.

If you have any question or suggestion related to this topic, feel free to ask it in the comment section.

Join The Conversation

Users are always welcome to leave comments about the articles, whether they are questions, comments, constructive criticism, old information, or notices of typos. Please keep in mind that all comments are moderated according to our comment policy.