Recent from talks
Contribute something
Nothing was collected or created yet.
Redirection (computing)
View on WikipediaThis article needs additional citations for verification. (April 2024) |

In computing, redirection is a form of interprocess communication, and is a function common to most command-line interpreters, including the various Unix shells that can redirect standard streams to user-specified locations. The concept of redirection is quite old, dating back to the earliest operating systems (OS).[citation needed] A discussion of the design goals for redirection can be found already in the 1971 description of the input-output subsystem of the Multics OS.[1] However, prior to the introduction of UNIX OS with its "pipes", redirection in operating systems was hard or even impossible to do.[2]
In Unix-like operating systems, programs do redirection with the dup2(2) system call, or its less-flexible but higher-level stdio analogues, freopen(3) and popen(3).[3]
Redirecting standard input and standard output
[edit]Redirection is usually implemented by placing certain characters between commands.
Basic
[edit]Typically, the syntax of these characters is as follows, using < to redirect input, and > to redirect output. command > file1 executes command, placing the output in file1, as opposed to displaying it at the terminal, which is the usual destination for standard output. This will clobber any existing data in file1.
Using command < file1 executes command, with file1 as the source of input, as opposed to the keyboard, which is the usual source for standard input.
command < infile > outfile combines the two capabilities: command reads from infile and writes to outfile
Variants
[edit]To append output to the end of the file, rather than clobbering it, the >> operator is used: command1 >> file1.
To read from a stream literal (an inline file, passed to the standard input), one can use a here document, using the << operator:
$ tr a-z A-Z << END_TEXT
> one two three
> uno dos tres
> END_TEXT
ONE TWO THREE
UNO DOS TRES
To read from a string, one can use a here string, using the <<< operator: tr a-z A-Z <<< "one two three", or:
$ NUMBERS="one two three"
$ tr a-z A-Z <<< "$NUMBERS"
ONE TWO THREE
Piping
[edit]
Programs can be run together such that one program reads the output from another with no need for an explicit intermediate file. command1 | command2 executes command1, using its output as the input for command2 (commonly called piping, with the "|" character being known as the "pipe").
The two programs performing the commands may run in parallel with the only storage space being working buffers (Linux allows up to 64K for each buffer) plus whatever work space each command's processing requires. For example, a "sort" command is unable to produce any output until all input records have been read, as the very last record received just might turn out to be first in sorted order. Dr. Alexia Massalin's experimental operating system, Synthesis, would adjust the priority of each task as they ran according to the fullness of their input and output buffers.[4]
This produces the same end result as using two redirects and a temporary file, as in:
$ command1 > tempfile
$ command2 < tempfile
$ rm tempfile
But here, command2 does not start executing until command1 has finished, and a sufficiently large scratch file is required to hold the intermediate results as well as whatever work space each task required. As an example, although DOS allows the "pipe" syntax, it employs this second approach. Thus, suppose some long-running program "Worker" produces various messages as it works, and that a second program, TimeStamp copies each record from stdin to stdout, prefixed by the system's date and time when the record is received. A sequence such as Worker | TimeStamp > LogFile.txt would produce timestamps only when Worker had finished, merely showing how swiftly its output file could be read and written.
A good example for command piping is combining echo with another command to achieve something interactive in a non-interactive shell, e.g. echo -e 'user\npass' | ftp localhost. This runs the ftp client with input user, press return, then pass.
In casual use, the initial step of a pipeline is often cat or echo, reading from a file or string. This can often be replaced by input indirection or a here string, and use of cat and piping rather than input redirection is known as useless use of cat. For example, the following commands:
$ cat infile | command
$ echo $string | command
$ echo -e 'user\npass' | ftp localhost
can be replaced by:
$ command < infile
$ command <<< $string
$ ftp localhost <<< $'user\npass'
As echo is often a shell-internal command, its use is not as criticized as cat, which is an external command.
Redirecting to and from the standard file handles
[edit]In Unix shells derived from the original Bourne shell, the first two actions can be further modified by placing a number (the file descriptor) immediately before the character; this will affect which stream is used for the redirection.[5] The Unix standard I/O streams are:[6]
| Handle | Name | Description |
|---|---|---|
| 0 | stdin | Standard input |
| 1 | stdout | Standard output |
| 2 | stderr | Standard error |
For example, command 2> file1 executes command, directing the standard error stream to file1.
In shells derived from csh (the C shell), the syntax instead appends the & (ampersand) character to the redirect characters, thus achieving a similar result. The reason for this is to distinguish between a file named '1' and stdout, i.e. cat file 2>1 vs cat file 2>&1. In the first case, stderr is redirected to a file named '1' and in the second, stderr is redirected to stdout.
Another useful capability is to redirect one standard file handle to another. The most popular variation is to merge standard error into standard output so error messages can be processed together with (or alternately to) the usual output. For example, find / -name .profile > results 2>&1 will try to find all files named .profile. Executed without redirection, it will output hits to stdout and errors (e.g. for lack of privilege to traverse protected directories) to stderr. If standard output is directed to file results, error messages appear on the console. To see both hits and error messages in file results, merge stderr (handle 2) into stdout (handle 1) using 2>&1.
If the merged output is to be piped into another program, the file merge sequence 2>&1 must precede the pipe symbol, thus, find / -name .profile 2>&1 | less
A simplified but non-POSIX conforming form of the command, command > file 2>&1 is (not available in Bourne Shell prior to version 4, final release, or in the standard shell Debian Almquist shell used in Debian/Ubuntu): command &>file or command >&file.
It is possible to use 2>&1 before ">" but the result is commonly misunderstood.
The rule is that any redirection sets the handle to the output stream independently.
So "2>&1" sets handle 2 to whatever handle 1 points to, which at that point usually is stdout.
Then ">" redirects handle 1 to something else, e.g. a file, but it does not change handle 2, which still points to stdout.
In the following example, standard output is written to file, but errors are redirected from stderr to stdout, i.e. sent to the screen: command 2>&1 > file.
To write both errors and standard output to file, the order should be reversed. Standard output would first be redirected to the file, then stderr would additionally be redirected to the stdout handle that has already been changed to point at the file: command > file 2>&1.
Chained pipelines
[edit]The redirection and piping tokens can be chained together to create complex commands. For example, sort infile | uniq -c | sort -n > outfile sorts the lines of infile in lexicographical order, writes unique lines prefixed by the number of occurrences, sorts the resultant output numerically, and places the final output in outfile.[7] This type of construction is used very commonly in shell scripts and batch files.
Redirect to multiple outputs
[edit]The standard command tee can redirect output from a command to several destinations:ls -lrt | tee xyz. This directs the file list output to both standard output and the file xyz.
See also
[edit]- Here-document, a way of specifying text for input in command-line shells
- Shell shoveling
- Command substitution
- Process substitution
- Console redirection
References
[edit]- ^ Feiertag & Organick 1972.
- ^ Kernighan & Morgan 1982, p. 780, Input/output redirection.
- ^ The GNU C Library Reference Manual for version 2.38 gnu.org
- ^ "KHB: Synthesis: An Efficient Implementation of Fundamental Operating Systems Services". lwn.net.
- ^ Nozaki, Roberto (April 21, 2022). "How to redirect shell command output". www.redhat.com.
- ^ "Redirections (Bash Reference Manual)". www.gnu.org.
- ^ "Piping and Redirecting Output in the Linux Terminal". Linux.org.
Sources
[edit]- Feiertag, R. J.; Organick, E. I. (1972). "The Multics input/output system". ACM SIGOPS Operating Systems Review. 6 (1/2): 35–38. doi:10.1145/850614.850622. ISSN 0163-5980.
- Kernighan, Brian W.; Morgan, Samuel P. (1982). "The UNIX Operating System: A Model for Software Design". Science. 215 (4534). American Association for the Advancement of Science: 779–783. eISSN 0036-8075. ISSN 1095-9203. JSTOR 1687467. Retrieved 2024-04-25.
External links
[edit]- : duplicate an open file descriptor – System Interfaces Reference, The Single UNIX Specification, Version 5 from The Open Group
- Redirection Definition by The Linux Information Project (LINFO)
- I/O Redirection in The Linux Documentation Project
- Redirection in Windows
- Creating a Child Process with Redirected Input and Output in Windows
Redirection (computing)
View on Grokipedia< for input from a file, > for output to a file (overwriting if it exists), and >> for appending output; the | operator enables piping output from one command to another's input.[1] Additional forms allow duplicating streams (e.g., 2>&1 to merge stderr with stdout) or using here-documents (<<) for inline input.[3] These mechanisms enhance scripting efficiency and automation in Unix-like systems, influencing modern environments like Linux and macOS.[4] Redirection's flexibility supports complex workflows, such as logging errors separately or chaining multiple commands without intermediate storage.[1]
Core Concepts
Standard Streams
In Unix-like operating systems, processes are provided with three default input/output streams to facilitate communication with their environment: standard input (stdin), standard output (stdout), and standard error (stderr). Standard input serves as the primary channel for receiving data into a program, typically from the keyboard in interactive sessions or from a file or another process in scripted operations. Standard output handles the normal results or data produced by a program, directing them to the display or another destination by default. Standard error, distinct from stdout, is dedicated to diagnostic messages, warnings, and error reports, ensuring that such information remains visible even if normal output is redirected elsewhere.[5][6] These streams are associated with specific file descriptors, which act as numeric handles for low-level I/O operations: 0 for stdin, 1 for stdout, and 2 for stderr. By convention, these descriptors are opened automatically when a process starts, linking the streams to the terminal device unless modified.[5][6] Conceptually, standard streams represent abstractions that treat diverse I/O targets—such as files, devices, or network sockets—as uniform byte streams, promoting portability and simplicity in program design. Each stream is unidirectional, allowing data flow in only one direction: input for stdin and output for both stdout and stderr, which aligns with the Unix philosophy of composable tools.[5][7] The standard streams originated in the early development of Unix during the 1970s at Bell Laboratories, where Ken Thompson and Dennis Ritchie established them as core elements to standardize inter-process and user I/O interactions, building on the system's file-based model.[8][7]File Descriptors
In Unix-like operating systems, file descriptors serve as small non-negative integers assigned by the kernel to represent open files, pipes, sockets, or devices within a specific process, acting as indices into the process's file descriptor table.[9] These descriptors provide a low-level abstraction for input/output operations, enabling processes to interact with system resources without direct knowledge of their underlying implementation. By convention, the lowest file descriptors are reserved for the standard streams: descriptor 0 for standard input (stdin), 1 for standard output (stdout), and 2 for standard error (stderr), which are automatically opened upon process creation.[5] Subsequent file descriptors are allocated sequentially, starting from the lowest available number greater than 2, ensuring efficient reuse of small integers for common operations. A key mechanism for implementing redirection involves duplicating file descriptors, as provided by system calls like dup() in C, which creates a new descriptor that refers to the same underlying open file description as the original, typically assigning the lowest available slot.[10] This duplication allows a process to redirect input or output by reassigning a standard descriptor (such as 1 for stdout) to point to a different resource, like a file or pipe, without altering the original. Each process maintains its own file descriptor table, limited in size—typically to 1024 entries in many Unix-like systems, though configurable via resource limits like ulimit—to prevent resource exhaustion.[11] Upon calling fork() to create a child process, the child inherits a copy of the parent's file descriptor table, with each descriptor in the child referring to the same open file descriptions as in the parent, facilitating shared access unless explicitly closed.[12]Basic Redirection Operations
Output Redirection
Output redirection in POSIX-compliant shells allows the standard output of a command, which is the default stream for normal output (file descriptor 1), to be directed to a file or other destination instead of the terminal.[1] This is achieved using specific operators that control whether the output overwrites or appends to the target file. The basic operator> redirects standard output to a file, overwriting its contents if the file already exists.[13] For example, in a POSIX shell like sh or bash, the command ls > listing.txt lists the current directory's contents and writes them to listing.txt, creating the file if it does not exist or truncating it to zero length otherwise.[1] The shell opens the file for writing, and if the noclobber option is enabled (via set -C), the redirection fails with an error if the file exists and is a regular file, preventing accidental overwrites.[13]
The append variant >> redirects standard output to a file without overwriting it, instead adding the new output at the end.[14] For instance, echo "text" >> log.txt appends the string "text" to log.txt, creating the file if necessary.[1] This operator uses the O_APPEND flag when opening the file, ensuring writes occur at the end-of-file position even in concurrent scenarios, though the initial open operation is not atomic.[14]
Key behaviors include permission checks performed by the shell before executing the command: the target file must be writable or creatable in its directory, with appropriate user permissions.[1] If the file cannot be opened due to insufficient permissions, the redirection fails: the shell reports a "permission denied" error to standard error, and the command is not executed.[1]
In multi-process scenarios, such as concurrent shell commands redirecting to the same file, race conditions can occur during the open-and-truncate phase with >, potentially allowing partial overwrites or interleaved writes if the operations are not synchronized.[15] The noclobber option mitigates some risks but introduces its own races, where multiple processes might check the file's existence before any truncation happens.[15] Appending with >> is generally safer for logging, as the O_APPEND flag ensures sequential addition, though the file must still be openable atomically.[14]
Common edge cases include redirecting to special files like /dev/null to suppress output entirely, as in command > /dev/null, where writes are discarded without error.[3] This treats /dev/null as a write-only sink, compatible with POSIX file handling. If the target is a non-regular file (e.g., a directory or device) that cannot accept output, the redirection fails similarly to permission issues, with errors directed to standard error.[1]
Input Redirection
Input redirection in computing refers to the mechanism in command-line shells that allows the standard input (stdin) of a command to be sourced from a file rather than the keyboard or terminal. In POSIX-compliant shells, this is achieved using the< operator, which redirects the contents of a specified file to the standard input stream (file descriptor 0 by default). The shell opens the file for reading before executing the command, applying expansions such as tilde, parameter, command, arithmetic, and quote removal to the filename.[1]
If the specified file does not exist or cannot be opened for reading due to permissions or other errors, the redirection fails: the shell reports an error message to standard error, and the command is not executed (in non-interactive shells, the shell exits with a non-zero status).[1] Unlike output redirection, input redirection operates in read-only mode and does not involve overwriting or appending to the source file; instead, the command reads sequentially until it encounters the end-of-file (EOF), at which point stdin is closed for that process. This EOF handling ensures that commands process the entire file content without requiring interactive input.[1][15]
Common examples in POSIX shells include counting lines in a file with wc -l < data.txt, which reads from data.txt instead of stdin, or displaying file contents via cat < input.txt > output.txt, where input is sourced from input.txt while output is redirected separately. These operations are particularly useful for feeding data to filter commands like grep to search for patterns in non-interactive files, such as grep "error" < log.txt, or to utilities like sort for ordering file contents without manual entry. In scenarios involving compilers or other tools that can process source from stdin, input redirection enables batch processing of code files, avoiding the need for keyboard input during execution.[16][1]
Piping and Command Chaining
Single Pipe
In computing, a single pipe operation, denoted by the vertical bar operator|, enables the redirection of the standard output (stdout) from one command to the standard input (stdin) of another command, creating a simple two-stage pipeline. This mechanism allows commands to be chained without intermediate files, promoting efficient data processing in Unix-like shells. The operator is a fundamental feature of POSIX-compliant shells, where it forms the basis for connecting the output of the left-hand command directly to the input of the right-hand command.[17]
The shell implements a single pipe by invoking the POSIX pipe() system call to create an anonymous pipe, which is a unidirectional FIFO (first-in, first-out) buffer managed by the kernel for interprocess communication. Upon encountering the | operator, the shell forks two child processes: one for each command. It then configures the pipe such that the write end (file descriptor 1) connects to the stdout of the first process, while the read end (file descriptor 0) connects to the stdin of the second process. Data written to the pipe by the first command flows through the kernel's buffer to the second command, with the processes executing concurrently; the shell waits for both to complete unless the pipeline is backgrounded.[18][17]
Buffering behavior in pipes depends on the context and the programs involved. At the kernel level, pipes use a fixed-size circular buffer (typically 64 KiB on modern systems), and writing blocks if the buffer fills before the reader consumes data. User-space programs, however, apply their own buffering via standard I/O libraries: output to pipes is typically fully buffered (accumulating data in chunks, often 4 KiB or more) when non-interactive, leading to potential delays if the reader is slow. In interactive shells, where stdout targets a terminal, line buffering is common, flushing after each newline; pipes, being non-terminal devices, default to full buffering unless explicitly modified (e.g., via stdbuf or program options). This can cause "stuck" output in pipelines until buffers fill or the writer exits.[19][20]
Common examples illustrate the utility of single pipes. For instance, listing processes and filtering for those containing "bash" uses ps aux | grep bash, where ps outputs process details to the pipe, and grep reads and filters lines matching the pattern. Another case is logging the current date while displaying it: date | tee log.txt, where tee reads from the pipe and writes to both stdout and the specified file, briefly introducing tee as a pipe consumer that duplicates input streams.[17]
Single pipes are inherently unidirectional, transmitting only stdout from the producer to stdin of the consumer, without involving stderr or bidirectional flow. This limits their use to linear data streams between exactly two commands, distinguishing them from file-based redirections that persist data on disk.[17]
Chained Pipelines
Chained pipelines extend the single pipe mechanism by connecting the standard output of one command to the input of the next in a sequence of multiple commands, enabling complex data flows without intermediate storage.[21][22] The syntax uses the pipe operator| repeatedly, as in command1 | command2 | command3, where the output from each preceding command serves as input to the subsequent one.[21]
In implementation, the shell creates a separate pipe for each connection and forks a new process (subshell) for every command in the chain, allowing them to execute concurrently while data streams through the pipes.[21][23] This process model ensures isolation between commands but coordinates their I/O via the established pipes.[24]
Chained pipelines offer performance benefits by eliminating the need for temporary files, reducing disk I/O overhead and avoiding filesystem clutter or potential errors from file management.[25] They are particularly efficient for data processing workflows, such as filtering, sorting, and aggregating streams in real time.[26]
A common example processes a file to remove duplicates after sorting: cat file.txt | sort | uniq, where cat reads the content, sort orders it, and uniq eliminates repeats.[21] Another workflow searches logs for errors, counts unique occurrences: find . -name "*.log" | xargs grep error | sort | uniq -c.[21]
For branching within a linear chain, the tee command duplicates output to both a file and the next pipe stage, as in command | tee output.log | next_command, extending the pipeline without disrupting the flow.[21]
Handling Multiple Streams
Error Stream Redirection
In computing, error stream redirection allows the standard error stream (stderr), associated with file descriptor 2, to be directed to a file or merged with other streams independently of standard output (stdout).[1] This capability is essential for separating diagnostic messages, such as error reports from commands, from normal program output, facilitating better debugging and logging practices.[3] The primary operators for redirecting stderr to a file are2> to overwrite the target file and 2>> to append to it. For instance, the command ls nonexist 2> error.log redirects the "No such file or directory" error from the ls utility to error.log, leaving stdout unaffected.[1] Similarly, compiling with gcc -o prog source.c 2> compile_errors.txt captures compilation warnings and errors in a dedicated file without mixing them with successful output.[3] These operators adhere to POSIX standards, ensuring portability across Unix-like systems.[1]
To merge stderr with stdout, the operator 2>&1 duplicates file descriptor 2 to match descriptor 1, sending both streams to the same destination. A common usage is command > output.txt 2>&1, which captures all output—normal and errors—in output.txt.[1] In Bash, this is shorthand as &> for overwriting or &>> for appending, equivalent to > file 2>&1 or >> file 2>&1, respectively; for example, command &> all_output.txt combines both streams into one file.[3] The order of redirections matters: placing 2>&1 after > file ensures merging occurs after stdout redirection.[1]
Stderr redirection is particularly useful for logging because the error stream remains unbuffered by default, providing immediate output of diagnostics without delays from buffering, unlike stdout which may be line-buffered or fully buffered depending on the context. This behavior supports real-time error monitoring in scripts and applications. These operators are consistent in POSIX-compliant shells, and Windows Command Prompt uses a similar 2> syntax for stderr redirection, though merging requires 2>&1.[1][27]
Multiple Output Targets
In Unix-like operating systems, redirecting output to multiple destinations simultaneously is commonly achieved using thetee command, which duplicates standard output to one or more files while also passing it through to standard output for further processing or display.[28] The tee command reads from standard input and writes the content verbatim to both standard output and the specified files, preserving original formatting including newlines.[29] This allows users to broadcast the output of a command, such as saving a full log to disk for archival purposes while viewing it in real-time or piping it to another tool.[29]
The basic syntax involves piping a command's output to tee followed by one or more file names, as in command | [tee](/page/Tee) file1 [file2 ...].[28] For instance, to list directory contents and save them to a file while displaying on screen, one can use ls -l | [tee](/page/Tee) listing.txt.[29] To direct output to multiple files without displaying it, the standard output of tee can be redirected to /dev/null, such as ls -l | [tee](/page/Tee) file1.txt file2.txt > /dev/null.[29] By default, tee overwrites existing files, but the -a option enables appending to avoid data loss.[28]
A practical example integrates tee into a pipeline for selective processing: ls | tee listing.txt | grep "doc" saves the complete directory listing to listing.txt while filtering and displaying only entries containing "doc" on screen.[29] This branching capability extends linear pipelines by splitting output streams without custom scripting.[29] While file descriptor duplication (e.g., using exec 3>&1 to copy stdout to a new descriptor and redirect it separately) offers low-level alternatives for multiple targets, tee provides a simpler, more portable solution for most shell-based workflows.[3]
For merging streams like standard error with output before splitting, constructs such as command 2>&1 | tee combined.log can precede tee, but the emphasis remains on duplicating stdout to distinct sinks rather than combining them.[29]
Advanced and Variant Techniques
Here Documents and Here Strings
Here documents provide a method for redirecting multi-line input directly into a command's standard input without the need for temporary files. The syntax involves the operator<< followed by a delimiter word, with the input content spanning from the subsequent line until a line containing only the delimiter terminates it.[1] For example, the command cat << EOF followed by lines of text and ending with EOF will output those lines as if read from a file.[30] This feature is standardized in POSIX and supported across Unix-like shells.[1]
If the delimiter is unquoted, the lines within the here document undergo parameter expansion, command substitution, arithmetic expansion, and quote removal, similar to double-quoted strings; backslashes escape the dollar sign, backquote, and newline but not other characters.[30] Quoting the delimiter, such as << "EOF", prevents these expansions, treating the content literally after quote removal from the delimiter itself.[1] An optional dash after the operator, as in <<-, strips leading tabs (but not spaces) from each line of input and from the delimiter line, facilitating indented script formatting while preserving the content's structure.[30] No pathname expansion occurs in either case, and trailing newlines are not removed.[1]
Here documents are commonly used in shell scripting to supply input for commands that expect multi-line data, such as generating SQL queries or email bodies. For instance, to perform arithmetic calculations, one might use bc << EOF followed by expressions like 5 * 7 and ending with EOF, which computes and outputs the result.[30] Another example involves creating configuration files inline: cat > config.txt << EOF with key-value pairs, terminated by EOF.[31]
Here strings, a Bash and Zsh extension not part of the POSIX standard, offer a concise way to redirect a single expanded word or string as input using the <<< operator.[30] The word undergoes tilde, parameter, variable, and command expansion before being supplied to the command's standard input, akin to an unquoted here document limited to one line.[30] For example, grep "pattern" <<< "some text to search" feeds the string directly for pattern matching, avoiding the need for echoing to a pipe.[30] This is useful for simple, inline string processing in scripts.
Limitations of here documents include the requirement that the delimiter appear alone on its terminating line without leading or trailing blanks, or the input will continue reading unexpectedly.[1] In unquoted variants, unintended variable expansion can pose security risks, such as command injection if user-supplied data is embedded without proper quoting, potentially leading to arbitrary code execution.[32] Here strings share similar expansion behaviors and thus inherit comparable risks, though their single-line nature limits exposure compared to multi-line documents.[30]
Process Substitution
Process substitution is a shell feature that treats the input or output of a command as a temporary file, allowing commands expecting filenames to operate on dynamic process streams without intermediate files. This enables complex integrations, such as comparing or combining outputs from multiple commands in non-linear ways.[33][34] In Bash and Zsh, process substitution uses two forms of syntax. The<(command) form generates a readable filename whose content is the standard output of the command, useful for providing input to tools that require file arguments. For example, diff <(sort file1) <(sort file2) compares the sorted contents of two files without creating temporary sorted copies. The >(command) form creates a writable filename that pipes input to the command's standard input, as in tar cf >(gzip) dir to compress a directory's archive on the fly. No spaces are allowed between the angle bracket and the parentheses in either syntax.[33][34][35]
Another practical example is paste <(cat file1) <(cat file2), which merges lines from two files side by side, treating the command outputs as if they were actual files; this is particularly valuable for utilities like diff, comm, or paste that do not natively support piped input from multiple sources. While simpler linear data flows can often use piping as an alternative, process substitution excels in scenarios requiring multiple inputs or outputs to converge on a single command.[34][36]
Under the hood, the shell implements process substitution by creating a temporary named pipe (FIFO) in a directory like /tmp or using a /dev/fd link to an open file descriptor, depending on system support. The enclosed command runs asynchronously in the background, with its input or output connected via the pipe or descriptor; the parent process then substitutes the resulting filename and waits for the background command to complete before proceeding. This ensures synchronization without blocking the main command.[33][34]
Process substitution is a non-POSIX extension, unavailable in basic POSIX sh implementations, but supported in advanced shells like Bash, Zsh, and KornShell (ksh). Windows PowerShell provides a similar capability through command substitution with $(command), which captures output as a string for integration, though it lacks the file-like interface of Unix process substitution.[33][34][37]