Redirections
Redirections control where command input and output go. They let you save output to files, read input from files, or otherwise manipulate how commands perform I/O operations.
What are file descriptors?
A file descriptor is a non-negative integer that identifies an open file or I/O channel in a process. When a process opens a file, the operating system assigns it a file descriptor, which the process uses to read from or write to that file.
The first three file descriptors have standard meanings:
- 0: Standard input – the source of input data
- 1: Standard output – the destination for command results
- 2: Standard error – the destination for error messages and diagnostics
By default, these are connected to the terminal, but they can be redirected to files or other destinations.
Redirection syntax
A redirection consists of a special operator followed by a target (such as a file or file descriptor). Redirections can appear anywhere in a simple command, or after the body of a compound command.
For example, the > operator redirects standard output to a file:
The < operator redirects standard input from a file:
(The read built-in reads a line from standard input into a variable.)
Redirection operators
Yash-rs supports these redirection operators:
- 
<(file): Redirects standard input from a file.
- 
>(file): Redirects standard output to a file.- If the clobbershell option is set (default),>behaves like>|.
- If clobberis not set,>fails if the file exists and is a regular file or a symlink to a non-existent file. Otherwise, it creates a new regular file or opens the existing non-regular one. This is useful for preventing accidental overwriting of files.
 
- If the 
- 
>|(file): Redirects standard output to a file, overwriting it if it exists.- Always overwrites existing files, regardless of the clobberoption.
- Truncates the file if it exists, or creates it if not.
 
- Always overwrites existing files, regardless of the 
- 
>>(file): Redirects standard output to a file, appending to it if it exists.- Appends to the file if it exists, or creates it if not.
 
- 
<>(file): Opens a file for both reading and writing.- Opens the file if it exists, or creates it if not.
 
- 
<&: Duplicates or closes standard input, depending on the target word:- If the word is a file descriptor number, standard input becomes a copy of that descriptor (which must be open for reading).
- If the word is -, standard input is closed. No error is reported if it is already closed.- If standard input is closed, commands that read from it will fail. To provide empty input, use < /dev/nullinstead.
 
- If standard input is closed, commands that read from it will fail. To provide empty input, use 
 
- 
>&: Duplicates or closes standard output, depending on the target word:- 
If the word is a file descriptor number, standard output becomes a copy of that descriptor (which must be open for writing). 
- 
If the word is -, standard output is closed. No error is reported if it is already closed.- If standard output is closed, commands that write to it will fail. To discard output, use > /dev/nullinstead.
 
- If standard output is closed, commands that write to it will fail. To discard output, use 
- 
For example, >&2redirects standard output to standard error:$ echo "error: please specify a user" >&2 error: please specify a user
 
- 
- 
>>|: This operator is reserved for future use, but is not currently implemented in yash-rs.
- 
<(: This operator is reserved for future use, but is not currently implemented in yash-rs.
- 
>(: This operator is reserved for future use, but is not currently implemented in yash-rs.
- 
<<(delimiter): Opens a here-document.
- 
<<-(delimiter): Opens a here-document with automatic removal of leading tabs.
- 
<<<(string): This operator is reserved for future use, but is not currently implemented in yash-rs.
Specifying file descriptors
Redirection operators starting with < default to standard input; those starting with > default to standard output. To redirect a different descriptor, prefix the operator with its number (no space):
For example, to redirect standard error to a file:
$ grep "pattern" input.txt 2> error.log
If you insert a space, the number is treated as a command argument, not a file descriptor:
Some shells allow using a variable name in braces {} instead of a file descriptor. For file-opening redirections, the shell allocates a new descriptor and assigns it to the variable. For descriptor-copying redirections, the shell uses the descriptor stored in the variable.
This is not yet implemented in yash-rs, but would look like:
$ exec {fd}> output.txt
$ echo "Hello, World!" >&$fd
$ cat output.txt
Hello, World!
Target word expansion
Except for here-documents, the word after a redirection operator is expanded before use. The following expansions are performed:
Pathname expansion may be supported in the future.
Persistent redirections
By default, redirections only apply to the command they are attached to. To make a redirection persist across multiple commands, use the exec built-in without arguments:
You can use the >& operator to save a file descriptor before redirecting it, and restore it later:
Semantic details
Applying a redirection to a compound command is different from applying it to a simple command inside the compound command. Each use of < opens a new file descriptor at the start of the file. If the redirection is inside a loop, the file descriptor is reset to the beginning on each iteration:
$ printf 'One\nTwo\nThree\n' > input.txt
$ while read -r line < input.txt; do
>     echo "Read: $line"
> done
Read: One
Read: One
Read: One
Read: One
Read: One
(The loop never ends…)
If a command has multiple redirections, they are applied in order. If several affect the same file descriptor, the last one takes effect:
Note the difference between > /dev/null 2>&1 and 2>&1 > /dev/null:
- > /dev/null 2>&1redirects both standard output and standard error to- /dev/null, discarding both.
- 2>&1 > /dev/nullredirects standard error to standard output, and then redirects standard output to- /dev/null. This means standard error is still printed to the terminal (or wherever standard output was originally directed).
$ cat /nonexistent/file > /dev/null 2>&1
$ cat /nonexistent/file 2>&1 > /dev/null
cat: /nonexistent/file: No such file or directory