1. Overview

Bash is a popular shell scripting language that allows us to execute commands and manipulate data. One of the features of Bash is the ability to use here-documents to provide multi-line input to a command or variable.

In this tutorial, we’ll explore the EOF marker and how to use EOF in several use cases.

We tested the code snippets in the article in Ubuntu 22.04 LTS.

2. What Is EOF?

End-of-file (EOF) is a marker that indicates we can’t read anything else from an input stream. It’s not a character, but a special signature that indicates the end of input or data.

For instance, we can use a loop that continues to read data from a file or user input until it encounters EOF:

$ cat file | while IFS = read -r line; do
  printf '%s\n' "Reading: $line"
done

The example above reads each line from the standard input and prints it to the standard output. It uses the IFS variable to trim trailing whitespace from the input. Also, it uses the -r option to prevent backslash escaping in the input. The loop continues until it reaches EOF since that is what’s hardcoded within the read command.

However, the EOF marker can be different things depending on the context.

3. How Is EOF Represented?

Although the reasoning behind EOF is similar, it can mean and be different things.

3.1. Minus One and End-Of-Transmission (EOT)

Different programming languages and tools provide distinct representations of EOF. For instance, in C and C++, the value -1 is used to represent EOF. Meanwhile, most shells including Bash use the Ctrl+D end-of-transmission character.

End-Of-Transmission (EOT) has a value of 4 and is one of the ASCII control characters. We can usually produce EOT with Ctrl+D and represent it as ^D in caret notation.

In Unix, the EOT character forces the terminal driver to immediately make available all the characters in its input buffer. When the input buffer is empty, a program reading from the terminal receives a count of zero bytes. This condition is interpreted as reaching the end of the file but its signal varies.

3.2. cat and EOF

We can use the cat command to see the behavior of EOF. If we run cat without any arguments, it accepts input from the keyboard and displays output on the screen. Typing a few characters like text without pressing Return adds them to the input buffer:

$ cat
texttext

When we then type Ctrl+D, cat accepts the characters we’ve entered up to that point. Subsequently, the program writes them to the screen. If they were already on the screen, we see them output again. If we enter Ctrl+D without typing any characters, it’ll terminate the input stream, and cat will conclude.

3.3. Here-Documents

Of course, we can also use EOF as a delimiter in a here-document:

$ command << EOF
text
EOF

The EOF tag in here-documents is an EOF signature, but we shouldn’t confuse it to be a character or command. It’s not part of the input or output, but a way to indicate where the input ends. It’s different from the EOF marker we use to signal the end of a file or input stream. This is because we can use any word or syntax that doesn’t appear in the text as a delimiter.

4. Conclusion

In this article, we learned what EOF is, how we represent it, and how we handle it in Bash. We also saw how to use EOF to terminate a program or a loop when reading data from user input. Notably, even though we mostly use EOF as a delimiter in here-documents, it doesn’t mean it’s a character or a variable that has a direct representation in Bash.