This question may sound a bit stupid, but I can not really see the difference between redirection and pipes.
Redirection is used to redirect the stdout/stdin/stderr, e.g. ls > log.txt
.
Pipes are used to give the output of a command as input to another command, e.g. ls | grep file.txt
.
But why are there two operators for the same thing?
Why not just write ls > grep
to pass the output through, isn't this just a kind of redirection also? What I am missing?
Pipe is used to pass output to another program or utility.
Redirect is used to pass output to either a file or stream.
Example:
thing1 > thing2
vsthing1 | thing2
thing1 > thing2
thing1
thing1
outputs will be placed in a file calledthing2
. (Note - ifthing2
exists, it will be overwritten)If you want to pass the output from program
thing1
to a program calledthing2
, you could do the following:thing1 > temp_file && thing2 < temp_file
which would
thing1
temp_file
thing2
, pretending that the person at the keyboard typed the contents oftemp_file
as the input.However, that's clunky, so they made pipes as a simpler way to do that.
thing1 | thing2
does the same thing asthing1 > temp_file && thing2 < temp_file
EDIT to provide more details to question in comment:
If
>
tried to be both "pass to program" and "write to file", it could cause problems in both directions.First example: You are trying to write to a file. There already exists a file with that name that you wish to overwrite. However, the file is executable. Presumably, it would try to execute this file, passing the input. You'd have to do something like write the output to a new filename, then rename the file.
Second example: As Florian Diesch pointed out, what if there's another command elsewhere in the system with the same name (that is in the execute path). If you intended to make a file with that name in your current folder, you'd be stuck.
Thirdly: if you mis-type a command, it wouldn't warn you that the command doesn't exist. Right now, if you type
ls | gerp log.txt
it will tell youbash: gerp: command not found
. If>
meant both, it would simply create a new file for you (then warn it doesn't know what to do withlog.txt
).From the Unix and Linux System Administration Handbook:
So my interpretation is: If it's command to command, use a pipe. If you are outputting to or from a file use the redirect.
If the meaning of
foo > bar
would depend on whether there is a command namedbar
that would make using redirection a lot harder and more error prone: Every time I want to redirect to a file I first had to check whether there's a command named like my destination file.Note:The answer reflects my own understanding of these mechanisms up to date, accumulated over research and reading of the answers by the peers on this site and unix.stackexchange.com, and will be updated as time goes on. Don't hesitate to ask questions or suggest improvements in the comments. I also suggest you try to see how syscalls work in shell with
strace
command. Also please don't be intimidated by the notion of internals or syscalls - you don't have to know or be able to use them in order to understand how shell does things, but they definitely help understanding.TL;DR
|
pipes are not associated with an entry on disk, therefore do not have an inode number of disk filesystem (but do have inode in pipefs virtual filesystem in kernel-space), but redirections often involve files, which do have disk entries and therefore have corresponding inode.lseek()
'able so commands can't read some data and then rewind back, but when you redirect with>
or<
usually it's a file which islseek()
able object, so commands can navigate however they please.dup2()
syscalls underneath the hood to provide copies of file descriptors, where actual flow of data occurs.exec
built-in command ( see this and this ), so if you doexec > output.txt
every command will write tooutput.txt
from then on.|
pipes are applied only for current command (which means either simple command or subshell likeseq 5 | (head -n1; head -n2)
or compound commands (but also please note that for such compound commands the amount of bytes thatread()
consumes will influence how much data is left on the sending end of the pipe for other commands inside the read end of the pipe ).echo "TEST" > file
andecho "TEST" >> file
both useopen()
syscall on that file (see also) and get file descriptor from it to pass it todup2()
. Pipes|
only usepipe()
anddup2()
syscall.mkfifo
) do involve typical file permissions and read-write-execute bits.apt
for instance, tends to not even write to stdout if it knows there's redirection).Introduction
In order to understand how these two mechanisms differ, it's necessary to understand their essential properties, the history behind the two, and their roots in C programming language. In fact, knowing what file descriptors are, and how
dup2()
andpipe()
system calls work is essential, as well aslseek()
. Shell is meant as a way of making these mechanisms abstract to the user, but digging deeper than the abstraction helps understand the true nature of shell's behavior.The Origins of Redirections and Pipes
According to Dennis Ritche's article Prophetic Petroglyphs, pipes originated from a 1964 internal memo by Malcolm Douglas McIlroy, at the time when they were working on Multics operating system. Quote:
What's apparent is that at the time programs were capable of writing to disk, however that was inefficient if output was large. To quote Brian Kernighan's explanation in Unix Pipeline video :
Thus conceptual difference is apparent: pipes are a mechanism of making programs talk to one another. Redirections - are way of writing to file at basic level. In both cases, shell makes these two things easy, but underneath the hood, there's whole lot of going on.
Going deeper: syscalls and internal workings of the shell
We start with the notion of file descriptor. File descriptors describe basically an open file (whether that's a file on disk, or in memory, or anonymous file), which is represented by an integer number. The two standard data streams (stdin,stdout,stderr) are file descriptors 0,1, and 2 respectively. Where do they come from ? Well, in shell commands the file descriptors are inherited from their parent - shell. And it's true in general for all processes - child process inherits parent's file descriptors. For daemons it is common to close all inherited file descriptors and/or redirect to other places.
Back to redirection. What is it really ? It's a mechanism that tells the shell to prepare file descriptors for command (because redirections are done by shell before command runs), and point them where the user suggested. The standard definition of output redirection is
That
[n]
there is the file descriptor number. When you doecho "Something" > /dev/null
the number 1 is implied there, andecho 2> /dev/null
.Underneath the hood this is done by duplicating file descriptor via
dup2()
system call. Let's takedf > /dev/null
. The shell will create a child process wheredf
runs, but before that it will open/dev/null
as file descriptor #3, anddup2(3,1)
will be issued, which makes a copy of file descriptor 3 and the copy will be 1. You know how you have two filesfile1.txt
andfile2.txt
, and when you docp file1.txt file2.txt
you'll have two same files, but you can manipulate them independently ? That's kinda the same thing happening here. Often you can see that before running, thebash
will dodup(1,10)
to make a copy file descriptor #1 which isstdout
( and that copy will be fd #10 ) in order to restore it later. Important is to note that when you consider built-in commands (which are part of shell itself, and have no file in/bin
or elsewhere) or simple commands in non-interactive shell, the shell doesn't create a child process.And then we have things like
[n]>&[m]
and[n]&<[m]
. This is duplicating file descriptors, which the same mechanism asdup2()
only now it's in the shell syntax, conveniently available for the user.One of the important things to note about redirection is that their order is not fixed, but is significant to how shell interprets what user wants. Compare the following:
The practical use of these in shell scripting can be versatile:
and many other.
Plumbing with
pipe()
anddup2()
So how do pipes get created ? Via
pipe()
syscall, which will take as input an array (aka list) calledpipefd
of two items of typeint
(integer). Those two integers are file descriptors. Thepipefd[0]
will be the read end of the pipe andpipefd[1]
will be the write end. So indf | grep 'foo'
,grep
will get copy ofpipefd[0]
anddf
will get a copy ofpipefd[1]
. But how ? Of course, with the magic ofdup2()
syscall. Fordf
in our example, let's saypipefd[1]
has #4, so the shell will make a child, dodup2(4,1)
(remember mycp
example ?), and then doexecve()
to actually rundf
. Naturally,df
will inherit file descriptor #1, but will be unaware that it's no longer pointing at terminal, but actually fd #4, which is actually the write end of the pipe. Naturally, same thing will occur withgrep 'foo'
except with different numbers of file descriptors.Now, interesting question: could we make pipes that redirect fd #2 as well, not just fd #1 ? Yes, in fact that's what
|&
does in bash. The POSIX standard requires shell command language to supportdf 2>&1 | grep 'foo'
syntax for that purpose, butbash
does|&
as well.What's important to note is that pipes always deal with file descriptors. There exists
FIFO
or named pipe, which has a filename on disk and let's you use it as a file, but behaves like a pipe. But the|
types of pipes are what's known as anonymous pipe - they have no filename, because they're really just two objects connected together. The fact that we're not dealing with files also makes an important implication: pipes aren'tlseek()
'able. Files, either in memory or on disk, are static - programs can uselseek()
syscall to jump to byte 120, then back to byte 10, then forward all the way to the end. Pipes are not static - they're sequential, and therefore you cannot rewind data you get from them withlseek()
. This is what makes some programs aware if they're reading from file or from pipe, and thus they can make necessary adjustments for efficient performance; in other words, aprog
can detect if I docat file.txt | prog
orprog < input.txt
. Real work example of that is tail.The other two very interesting property of pipes is that they have a buffer, which on Linux is 4096 bytes, and they actually have a filesystem as defined in Linux source code ! They're not simply an object for passing data around, they are a datastructure themselves ! In fact, because there exists pipefs filesystem, which manages both pipes and FIFOs, pipes have an inode number on their respective filesystem:
On Linux pipes are uni-directional, just like redirection. On some Unix-like implementations - there are bi-directional pipes. Although with magic of shell scripting, you can make bi-directional pipes on Linux as well.
See Also:
pipe()
syscall anddup2()
.<<
,<<<
are implemented as anonymous (unlinked) temp files inbash
andksh
, while< <()
uses anonymous pipes ;/bin/dash
uses pipes for<<
. See What's the difference between <<, <<< and < < in bash?There's a vital difference between the two operators:
ls > log.txt
--> This command sends the output to the log.txt file.ls | grep file.txt
--> This command sends the output of the ls to grep command through the use of pipe (|
), and the grep command searches for file.txt in the in the input provided to it by the previous command.If you had to perform the same task using the first scenario, then it would be:
So a pipe (with
|
) is used to send the output to other command, whereas redirection (with>
) is used to redirect the output to some file.There's a big syntactic difference between the two:
You can think of redirects like this:
cat [<infile] [>outfile]
. This implies order doesn't matter:cat <infile >outfile
is the same ascat >outfile <infile
. You can even mix redirects up with other arguments:cat >outfile <infile -b
andcat <infile -b >outfile
are both perfectly fine. Also you can string together more than one input or output (inputs will be read sequentially and all output will be written to each output file):cat >outfile1 >outfile2 <infile1 <infile2
. The target or source of a redirect can be either a filename or the name of a stream (like &1, at least in bash).But pipes totally separate one command from another command, you can't mix them in with arguments:
The pipe takes everything written to standard output from command1 and sends it to the standard input of command2.
You can also combine piping and redirection. For example:
The first
cat
will read lines from infile, then simultaneously write each line to outfile and send it to the secondcat
.In the second
cat
, standard input first reads from the pipe (the contents of infile), then reads from infile2, writing each line to outfile2. After running this, outfile will be a copy of infile, and outfile2 will contain infile followed by infile2.Finally, you actually do something really similar to your example using "here string" redirection (bash family only) and backticks:
will give the same result as
But I think the redirection version will first read all of the output of ls into a buffer (in memory), and then feed that buffer to grep one line at a time, whereas the piped version will take each line from ls as it emerges, and pass that line to grep.
To add to the other answers, there are subtle semantic difference too - e.g. pipes close more readily than redirects:
In the first example, when the first call to
head
finishes, it closes the pipe, andseq
terminates, so there's no input available for the secondhead
.In the second example, head consumes the first line, but when it closes it's own
stdin
pipe, the file remains open for the next call to use.The third example shows that if we use
read
to avoid closing the pipe it is still available within the subprocess.So the "stream" is the thing that we shunt data through (stdin etc), and is the same in both cases, but the pipe connects streams from two processes, where a redirection connects a streams between a process and a file, so you can see source of both the similarities and differences.
P.S. If you're as curious about and/or surprised by those examples as I was, you can get dig in further using
trap
to see how the processes resolve, E.g:Sometimes the first process closes before
1
is printed, sometimes afterwards.I also found it interesting to use
exec <&-
to close the stream from the redirection to approximate the behaviour of the pipe (albeit with an error):I've hit a problem with this in C today. Essentially Pipe's have different semantics to redirects as well, even when sent to
stdin
. Really I think given the differences, pipes should go somewhere other thanstdin
, so thatstdin
and lets call itstdpipe
(to make an arbitrary differential) can be handled in different ways.Consider this. When piping one program output to another
fstat
seems to return zero as thest_size
despitels -lha /proc/{PID}/fd
showing that there is a file. When redirecting a file this is not the case (at least on debianwheezy
,stretch
andjessie
vanilla and ubuntu14.04
,16.04
vanilla.If you
cat /proc/{PID}/fd/0
with a redirection you'll be able to repeat to read as many times as you like. If you do this with a pipe you'll notice that the second time you run the task consecutively, you don't get the same output.