Understanding Shell Redirection and File Descriptors in Linux

In Linux shells, redirection alters the source or destination of data streams used by commands. Input redirection changes where a program reads its input from, while output redirection changes where it sends its results. By default, standard input comes from the keyboard (file descriptor 0), and standard output and error go to the terminal (descriptors 1 and 2).

Kernel View: File Descriptors and Their Tables

The kernel represents open files as entries in several structures:

  • Per-proces file descriptor table – maps integer descriptors to open file handles.
  • System-wide open file table – tracks file offset, access mode, and reference count.
  • Inode table – stores metadata such as permissions, timestamps, and disk locatino.

Descriptors are non-negative integers. Commonly preassigned values are:

Descriptor Symbolic Name Typical Device Description
0 stdin Keyboard Standard input stream
1 stdout Terminal Normal output stream
2 stderr Terminal Error output stream

New files opened by a process receive the smallest unused descriptor ≥ 3. Reusing descriptors above 9 may cause conflicts because they can be reserved internally.

Descriptors may refer to the same underlying file via duplication (dup, dup2, fcntl) or inheritance (e.g., after fork). Multiple processes can share descriptors pointing to the same inode, and a single process may have distinct descriptors referring to different files.

Output Redirection Mechanics

Redirecting output substitutes the target of a descriptor. Overwriting uses >, appending uses >>. If the descriptor number is omitted, 1 is assumed for output.

Examples (with renamed variables for clarity):

# Send normal output to out.log, overwrite if exists
cmd 1>out.log

# Append errors to err.log
cmd 2>>err.log

# Merge both streams into one file (overwrite)
cmd 1>combined.log 2>&1

# Alternative merged syntax
cmd &>combined.log

# Separate outputs
cmd 1>ok.log 2>fail.log

Special device /dev/null discards any data sent to it:

cmd >/dev/null

Note spacing: 1 >file writes literal "1" to file; correct form is 1>file.

Input Redirection Mechanics

Input redirection replaces the source of descriptor 0. Syntax: [N]<source. Omitting N defaults to 0.

# Feed file content to a command
wc -l <input.txt

# Here-document until marker STOP
wc -l <<STOP
line1
line2
STOP

# Transform input file into output file
sort <unsorted.txt >sorted.txt

# Loop reading lines
while read line; do
  echo "Got: $line"
done <data.txt

Here-strings provide another compact form:

grep pattern <<<"single line input"

Manipulating Descriptors in Shell

Shells allow dynamic reassignment using exec:

Duplication

N>&M makes descriptor N refer to the same resource as M.

# Make fd 3 point to current stdout
exec 3>&1
# Now redirect stdout to file; fd 3 still points to terminal
exec >log.txt
echo "written to file"
# Restore stdout from saved fd 3
exec 1>&3 3>&-
echo "back to terminal"

Closing

N>&- closes descriptor N.

exec 4>&-   # close fd 4

Bidirectional Binding

N<>file opens file for both reading and writing on descriptor N.

exec 5<>shared.txt
read -n 3 <&5
echo -n X >&5

Moving Descriptors

N>&M- moves M to N and closes M.

exec 6>&1   # backup stdout
exec >temp.log
# ... operations ...
exec 1>&6-  # restore and close backup

Persistent Changes with exec

Without exec, redirections apply only to a single command. With exec, they persist until explicitly changed or shell termination.

Example preserving original stdin:

#!/bin/bash
exec 7<&0      # save original stdin
exec <values.txt
sum=0
while read num; do
  ((sum+=num))
done
echo "Total: $sum"
exec 0<&7 7<&-  # restore and close backup

To return output to the controlling terminal regardless of prior redirection:

exec >/dev/tty

Practical Scenarios

In-place File Update

echo "abcdefghij" >demo.txt
exec 8<>demo.txt
read -n 4 <&8
printf '.' >&8
exec 8>&-
cat demo.txt   # shows abcd.efghij

Temporary Log Capture

exec 9>&1
exec >session.log
echo "Session start"
# ... commands ...
exec 1>&9 9>&-
echo "Back on screen"

Remote Public Key Injection

ssh user@host -p2222 'mkdir -p .ssh && cat >> .ssh/authorized_keys' <~/.ssh/id_rsa.pub

This runs remote commands creating .ssh if needed, then appends local public key into authorized keys via input redirection.

Tags: Linux Shell Redirection File Descriptor IO Management

Posted on Fri, 08 May 2026 17:08:06 +0000 by love_php