关于管道在 Bash 中如何工作的简单解释是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9834086/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is a simple explanation for how pipes work in Bash?
提问by Village
I often use pipes in Bash, e.g.:
我经常在 Bash 中使用管道,例如:
dmesg | less
Although I know what this outputs, it takes dmesg
and lets me scroll through it with less
, I do not understand what the |
is doing. Is it simply the opposite of >
?
虽然我知道这会输出什么,但它需要dmesg
让我滚动浏览它less
,但我不明白|
它在做什么。是不是正好相反>
?
- Is there a simple, or metaphorical explanation for what
|
does? - What goes on when several pipes are used in a single line?
- Is the behavior of pipes consistent everywhere it appears in a Bash script?
- 是否有一个简单的或隐喻的解释
|
? - 在一条生产线上使用多个管道时会发生什么?
- 管道在 Bash 脚本中出现的任何地方的行为是否一致?
回答by quanticle
A Unix pipe connects the STDOUT (standard output) file descriptor of the first process to the STDIN (standard input) of the second. What happens then is that when the first process writes to its STDOUT, that output can be immediately read (from STDIN) by the second process.
Unix 管道将第一个进程的 STDOUT(标准输出)文件描述符连接到第二个进程的 STDIN(标准输入)。然后发生的情况是,当第一个进程写入其 STDOUT 时,第二个进程可以立即(从 STDIN)读取该输出。
Using multiple pipes is no different than using a single pipe. Each pipe is independent, and simply links the STDOUT and STDIN of the adjacent processes.
使用多个管道与使用单个管道没有什么不同。每个管道都是独立的,只是简单地链接相邻进程的 STDOUT 和 STDIN。
Your third question is a little bit ambiguous. Yes, pipes, as such, are consistent everywhere in a bash script. However, the pipe character |
can represent different things. Double pipe (||
), represents the "or" operator, for example.
你的第三个问题有点模棱两可。是的,管道本身在 bash 脚本中的任何地方都是一致的。但是,管道字符|
可以代表不同的东西。例如,双管道 ( ||
) 表示“或”运算符。
回答by rkachach
In Linux (and Unix in general) each process has three default file descriptors:
在 Linux(以及一般的 Unix)中,每个进程都有三个默认的文件描述符:
- fd #0 Represents the standard input of the process
- fd #1 Represents the standard output of the process
- fd #2 Represents the standard error output of the process
- fd #0 代表进程的标准输入
- fd #1 代表进程的标准输出
- fd #2 代表进程的标准错误输出
Normally, when you run a simple program these file descriptors by default are configured as following:
通常,当您运行一个简单的程序时,这些文件描述符默认配置如下:
- default input is read from the keyboard
- Standard output is configured to be the monitor
- Standard error is configured to be the monitor also
- 从键盘读取默认输入
- 标准输出配置为监视器
- 标准错误也配置为监视器
Bash provides several operators to change this behavior (take a look to the >, >> and < operators for example). Thus, you can redirect the output to something other than the standard output or read your input from other stream different than the keyboard. Specially interesting the case when two programs are collaboratingin such way that one uses the output of the other as its input. To make this collaboration easy Bash provides the pipe operator |
. Please note the usage of collaboration instead of chaining. I avoided the usage of this term since in fact a pipe is not sequential. A normal command line with pipes has the following aspect:
Bash 提供了几个操作符来改变这种行为(例如查看 >、>> 和 < 操作符)。因此,您可以将输出重定向到标准输出以外的其他内容,或者从不同于键盘的其他流中读取您的输入。当两个程序以一种使用另一个程序的输出作为其输入的方式进行协作时,这种情况特别有趣。为了使这种协作变得容易,Bash 提供了管道操作符|
。请注意使用协作而不是链接。我避免使用这个术语,因为实际上管道不是顺序的。带有管道的普通命令行具有以下方面:
> program_1 | program_2 | ... | program_n
The above command line is a little bit misleading: user could think that program_2 gets its input once the program_1 has finished its execution, which is not correct. In fact, what bash does is to launch ALLthe programs in parallel and it configures the inputs outputs accordingly so every program gets its input from the previous one and delivers its output to the next one (in the command line established order).
上面的命令行有点误导:用户可能认为 program_1 执行完后 program_2 得到了它的输入,这是不正确的。事实上,bash 所做的是并行启动所有程序,并相应地配置输入输出,以便每个程序从前一个程序获取输入并将其输出传递给下一个程序(以命令行建立的顺序)。
Following is a simple example from Creating pipe in Cof creating a pipe between a parent and child process. The important part is the call to the pipe() and how the parent closes fd1(writing side) and how the child closes fd1(writing side). Please, note that the pipe is a unidirectionalcommunication channel. Thus, data can only flow in one direction: fd1towards fd[0]. For more information take a look to the manual page of pipe().
以下是在 C中创建管道的一个简单示例,该示例在父进程和子进程之间创建管道。重要的部分是调用 pipe() 以及父级如何关闭 fd 1(写入端)以及子级如何关闭 fd 1(写入端)。请注意,管道是单向通信通道。因此,数据只能沿一个方向流动:fd 1流向 fd[0]。有关更多信息,请查看 pipe() 的手册页。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return(0);
}
Last but not least, when you have a command line in the form:
最后但并非最不重要的是,当您有以下形式的命令行时:
> program_1 | program_2 | program_3
The return code of the whole line is set to the lastcommand. In this case program_3. If you would like to get an intermediate return code you have to set the pipefailor get it from the PIPESTATUS.
整行的返回码设置为最后一条命令。在这种情况下 program_3。如果您想获得中间返回码,您必须设置pipefail或从PIPESTATUS获取它。
回答by Eduardo Ivanec
Every standard process in Unix has at least three file descriptors, which are sort of like interfaces:
Unix 中的每个标准进程至少有三个文件描述符,它们有点像接口:
- Standard output, which is the place where the process prints its data (most of the time the console, that is, your screen or terminal).
- Standard input, which is the place it gets its data from (most of the time it may be something akin to your keyboard).
- Standard error, which is the place where errors and sometimes other out-of-band data goes. It's not interesting right now because pipes don't normally deal with it.
- 标准输出,这是进程打印其数据的地方(大部分时间是控制台,即您的屏幕或终端)。
- 标准输入,这是它从中获取数据的地方(大多数情况下它可能类似于您的键盘)。
- 标准错误,这是错误和有时其他带外数据出现的地方。现在并不有趣,因为管道通常不处理它。
The pipe connectsthe standard output of the process to the left to the standard input of the process of the right. You can think of it as a dedicated program that takes care of copying everything that one program prints, and feeding it to the next program (the one after the pipe symbol). It's not exactly that, but it's an adequate enough analogy.
管道将左侧进程的标准输出连接到右侧进程的标准输入。您可以将其视为一个专用程序,负责复制一个程序打印的所有内容,并将其提供给下一个程序(管道符号之后的程序)。不完全是这样,但这是一个足够的类比。
Each pipe operates on exactly two things: the standard output coming from its left and the input stream expected at its right. Each of those could be attached to a single process or another bit of the pipeline, which is the case in a multi-pipe command line. But that's not relevant to the actual operation of the pipe; each pipe does its own.
每个管道都作用于两件事:来自其左侧的标准输出和预期在其右侧的输入流。每一个都可以附加到单个进程或管道的另一位,这是多管道命令行的情况。但这与管道的实际操作无关;每个管道都有自己的。
The redirection operator (>
) does something related, but simpler: by default it sends the standard output of a process directly to a file. As you can see it's not the opposite of a pipe, but actually complementary. The opposite of >
is unsurprisingly <
, which takes the content of a file and sends it to the standard input of a process (think of it as a program that reads a file byte by byte and types it in a process for you).
重定向运算符 ( >
) 执行一些相关但更简单的操作:默认情况下,它将进程的标准输出直接发送到文件。正如您所看到的,它不是管道的对立面,而是实际上是互补的。>
毫不奇怪<
,相反,它获取文件的内容并将其发送到进程的标准输入(将其视为一个程序,它可以逐字节读取文件并将其键入到进程中)。
回答by Halim Qarroum
A pipe takes the output of a process, by output I mean the standard output (stdout
on UNIX) and passes it on the standard input (stdin)
of another process. It is not the opposite of the simple right redirection >
which purpose is to redirect an output to another output.
管道接收进程的输出,输出是指标准输出(stdout
在 UNIX 上)并将其传递(stdin)
到另一个进程的标准输入。它与简单的右重定向不同>
,其目的是将一个输出重定向到另一个输出。
For example, take the echo command on Linux which is simply printing a string passed in parameter on the standard output. If you use a simple redirect like :
例如,在 Linux 上使用 echo 命令,它只是在标准输出上打印传入参数的字符串。如果您使用简单的重定向,如:
echo "Hello world" > helloworld.txt
the shell will redirect the normal output initially intended to be on stdout and print it directly into the file helloworld.txt
.
shell 将重定向最初打算在 stdout 上的正常输出并将其直接打印到文件中helloworld.txt
。
Now, take this example which involves the pipe :
现在,以这个涉及管道的例子为例:
ls -l | grep helloworld.txt
ls -l | grep helloworld.txt
The standard output of the ls
command will be outputed at the entry of grep, so how does this work?
ls
命令的标准输出会在grep的入口处输出,那么这是如何工作的呢?
Programs such as grep
when they're being used without any arguments are simply reading and waiting for something to be passed on their standard input (stdin)
. When they catch something, like the ouput of the ls command, grep acts normally by finding an occurence of what you're searching for.
诸如grep
当它们在没有任何参数的情况下使用时的程序只是读取并等待在其标准输入上传递的内容(stdin)
。当它们捕获某些东西时,例如 ls 命令的输出,grep 会通过查找您正在搜索的内容来正常运行。
回答by Xander
Pipes are very simple like this.
管道就像这样非常简单。
You have the output of one command. You can provide this output as the input into another command using pipe. You can pipe as many commands as you want.
你有一个命令的输出。您可以使用管道将此输出作为输入提供给另一个命令。您可以根据需要通过管道传输任意数量的命令。
ex: ls | grep my | grep files
例如: ls | 我的 | grep文件
This first lists the files in the working directory. This output is checked by the grep command for the word "my". The output of this is now into the second grep command which finally searches for the word "files". Thats it.
这首先列出了工作目录中的文件。此输出由 grep 命令检查单词“my”。这个输出现在进入第二个 grep 命令,它最终搜索单词“files”。就是这样。
回答by franka
The pipe operator takes the output of the first command, and 'pipes' it to the second one by connecting stdin and stdout. In your example, instead of the output of dmesg command going to stdout (and throwing it out on the console), it is going right into your next command.
管道运算符获取第一个命令的输出,并通过连接 stdin 和 stdout 将其“管道化”到第二个命令。在您的示例中,不是将 dmesg 命令的输出发送到标准输出(并将其扔到控制台上),而是直接进入您的下一个命令。
回答by Shiplu Mokaddim
|
puts the STDOUT of the command at left side to the STDIN of the command of right side.If you use multiple pipes, it's just a chain of pipes. First commands output is set to second commands input. Second commands output is set to next commands input. An so on.
It's available in all Linux/widows based command interpreter.
|
将左侧命令的 STDOUT 放在右侧命令的 STDIN 中。如果您使用多个管道,它只是一串管道。第一个命令输出设置为第二个命令输入。第二个命令输出设置为下一个命令输入。等等。
它在所有基于 Linux/widows 的命令解释器中可用。
回答by cctan
If you treat each unix command as a standalone module,
but you need them to talk to each other using text as a consistentinterface,
how can it be done?
如果您将每个 unix 命令都视为一个独立的模块,
但您需要它们使用文本作为一致的接口相互通信,那
该怎么办?
cmd input output
echo "foobar" string "foobar"
cat "somefile.txt" file *string inside the file*
grep "pattern" "a.txt" pattern, input file *matched string*
You can say |
is a metaphor for passing the baton in a relay marathon.
Its even shaped like one!cat -> echo -> less -> awk -> perl
is analogous to cat | echo | less | awk | perl
.
你可以说|
是在接力马拉松中传递接力棒的比喻。
它甚至形状像一个!cat -> echo -> less -> awk -> perl
类似于cat | echo | less | awk | perl
.
cat "somefile.txt" | echo
cat
pass its output for echo
to use.
cat "somefile.txt" | echo
cat
传递其输出以echo
供使用。
What happens when there is more than one input?cat "somefile.txt" | grep "pattern"
There is an implicit rule that says "pass it as input filerather than pattern" for grep
.
You will slowly develop the eye for knowing which parameter is which by experience.
当有多个输入时会发生什么?cat "somefile.txt" | grep "pattern"
还有,说:“把它作为一个隐含的规则输入文件,而不是模式”进行grep
。
您将慢慢培养通过经验知道哪个参数是哪个参数的眼睛。