Skip to content

Input Redirection in Linux: stdin, Here Documents and Here Strings Explained

Updated 4 min read

Updated: 22 October 2026 · Applies to: bash 5.3 on Ubuntu 26.04 LTS and bash 5.1 on AlmaLinux 9; the same syntax works in bash on any Linux distribution

Input redirection feeds a file, or text you type in the script, to a command’s standard input instead of the keyboard. command < file reads from a file, command <<EOF reads the lines that follow until EOF (a here document), and command <<< "text" reads one string (a here string).

stdin, stdout and stderr

Every command starts with three open channels, each with a number called a file descriptor:

  • 0, standard input (stdin): where the command reads from. Normally the keyboard.
  • 1, standard output (stdout): normal output. Normally the screen.
  • 2, standard error (stderr): error messages. Also the screen.

Input redirection changes descriptor 0. For the output side (>, >>, 2>, 2>&1), see redirecting command output.

1. Read from a file with <

$ wc -l fruit.txt
3 fruit.txt
$ wc -l < fruit.txt
3

With <, the shell opens the file and wc only sees a stream of text, so it prints no file name. That is handy in scripts where you want just the number.

You can combine input and output redirection in one command:

sort < fruit.txt > sorted.txt

The everyday server example is importing a database dump: mysql shopdb < backup.sql sends the SQL file to the client as if you had typed it (see dumping and importing MySQL or MariaDB databases). The same works for SQLite: sqlite3 test.db < dump.sql.

If the file does not exist, the command never runs and bash reports:

bash: nofile.txt: No such file or directory

2. Read a file line by line

while read -r line; do
    echo "Fruit: $line"
done < fruit.txt
Fruit: banana
Fruit: apple
Fruit: cherry

The < fruit.txt after done feeds the whole loop. -r stops read from treating backslashes as escape characters.

3. Here documents (<<)

A here document sends several lines written in the script itself. It is the usual way to write a config file from a script:

name=web01
cat <<EOF
Server: $name
User: $(whoami)
EOF
Server: web01
User: root

Variables and commands are expanded. Put the first delimiter in quotes to keep the text exactly as written, which is what you want for config files full of $ signs:

cat > /tmp/site.conf <<'EOF'
server_name example.com;
root /var/www/example;
EOF

With <<'EOF', a line such as Server: $name stays exactly Server: $name. With <<-EOF, bash removes leading tab characters (not spaces) from each line and from the closing EOF, so you can indent the block inside an if or a function. The closing word must be alone on its line.

4. Here strings (<<<)

A here string sends one line, followed by a newline:

$ tr a-z A-Z <<< "hello $name"
HELLO WEB01
$ read -r first second <<< "alpha beta"; echo "$first / $second"
alpha / beta

This also avoids a classic pipe trap. The bash manual explains that each part of a pipeline runs in its own subshell, so a variable set by read at the end of a pipe disappears:

$ echo "hello" | read -r x; echo "x=[$x]"
x=[]
$ read -r y <<< "hello"; echo "y=[$y]"
y=[hello]

5. Other file descriptors and process substitution

You can open a file on another descriptor and read from it step by step:

exec 3< fruit.txt      # open fruit.txt as descriptor 3
read -r a <&3          # first line
read -r b <&3          # second line
exec 3<&-              # close descriptor 3
echo "$a $b"           # banana apple

Process substitution, <(command), lets a command read another command’s output as if it were a file. For example, compare two lists after sorting them, without temporary files:

diff <(sort list1.txt) <(sort list2.txt)

Redirection and sudo

Your own shell opens the file, before sudo starts. So this fails for a normal user even though the command runs as root:

$ sudo wc -l < /etc/shadow
bash: /etc/shadow: Permission denied

Let the root command open the file instead: sudo wc -l /etc/shadow, or sudo sh -c 'wc -l < /etc/shadow'. The same applies to output: sudo echo text > /etc/file fails for the same reason.

Quick reference

  • cmd < file: read stdin from a file.
  • cmd <<EOF ... EOF: here document, with expansion.
  • cmd <<'EOF': here document, text kept literally.
  • cmd <<-EOF: here document, leading tabs removed.
  • cmd <<< "text": here string.
  • cmd <&3: read from descriptor 3; exec 3<&- closes it.
  • cmd <(other): read another command’s output as a file.

Official documentation: GNU bash manual: Redirections.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Linux server management

hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.

Was this answer helpful?

Still stuck? Open a ticket