Redirection

Redirection connects command input/output to files and file descriptors.

Source: src/io/fd_redirection.f90, src/execution/executor.f90

Output Redirection

Redirect stdout

command > file        # Write stdout to file (truncate)
command >> file       # Append stdout to file
command 1> file       # Explicit stdout (same as >)
command 1>> file      # Explicit append

Redirect stderr

command 2> file       # Write stderr to file
command 2>> file      # Append stderr to file

Redirect both

command &> file       # Both stdout and stderr to file
command &>> file      # Append both
command > file 2>&1   # Redirect stdout, then stderr to stdout
command 2>&1 > file   # Wrong order! stderr goes to original stdout

Discard output

command > /dev/null           # Discard stdout
command 2> /dev/null          # Discard stderr
command &> /dev/null          # Discard both
command > /dev/null 2>&1      # Discard both (portable)

Input Redirection

From file

command < file        # Read stdin from file
command 0< file       # Explicit stdin

Here-document

command << DELIMITER
content
more content
DELIMITER

See Heredocs for details.

Here-string

command <<< "string"
grep pattern <<< "$variable"
read first rest <<< "one two three"

File Descriptor Operations

Duplicate descriptors

command 2>&1          # stderr to stdout
command 1>&2          # stdout to stderr
command >&2           # stdout to stderr (shorthand)

Close descriptors

command 2>&-          # Close stderr
command <&-           # Close stdin

Open file on descriptor

exec 3> file          # Open fd 3 for writing
echo "data" >&3       # Write to fd 3
exec 3>&-             # Close fd 3

exec 4< file          # Open fd 4 for reading
read line <&4         # Read from fd 4
exec 4<&-             # Close fd 4

Read and write

exec 3<> file         # Open fd 3 for read/write

Noclobber

With set -C (noclobber), > fails if file exists:

set -C                # Enable noclobber
echo "data" > file    # Fails if file exists
echo "data" >| file   # Force overwrite anyway

Redirection Order

Redirections are processed left to right:

# stderr to stdout, then stdout to file
command > file 2>&1   # Both go to file

# stdout to file, then stderr to original stdout
command 2>&1 > file   # Only stdout to file, stderr to terminal

Combining with Pipes

command 2>&1 | grep pattern    # Grep both stdout and stderr
command |& grep pattern        # Same (bash shorthand)

Examples

Log both stdout and stderr

./script.sh > output.log 2>&1
./script.sh &> output.log      # Same

Separate stdout and stderr

./script.sh > stdout.log 2> stderr.log

Append to log

echo "$(date): Event" >> app.log

Process substitution

diff <(cmd1) <(cmd2)           # Compare outputs
tee >(process) < input         # Send to process and stdout

See Pipes for process substitution details.

Safe file overwrite

# Read and write same file
{ rm file && cmd > file; } < file

Redirect within function

log() {
    echo "[$(date)] $*" >> /var/log/app.log
}

Built-in exec

exec with no command makes redirections permanent:

exec > output.log     # All subsequent stdout goes to file
exec 2>&1             # stderr follows stdout

echo "This goes to output.log"
echo "So does this" >&2

To restore:

exec 3>&1             # Save stdout to fd 3
exec > output.log     # Redirect stdout
# ... commands ...
exec 1>&3             # Restore stdout
exec 3>&-             # Close fd 3

File Descriptor Limits

Standard descriptors:

  • 0: stdin
  • 1: stdout
  • 2: stderr
  • 3-9: Available for user scripts

Return Values

Redirection errors (file not found, permission denied) cause the command to fail with non-zero exit status. The error message is printed to stderr.

cat < nonexistent     # Error: No such file
echo "hi" > /readonly # Error: Permission denied