管|重定向< >优先权

时间:2012-10-17 19:37:26

标签: bash unix redirect command pipe

我想弄清楚什么时候管道或重定向< >在命令中优先?

这是我的想法,但需要确认这是它的工作原理。

示例1:

sort < names | head
The pipe runs first:  names|head   then it sorts what is returned from names|head

示例2:

ls | sort > out.txt
This one seems straight forward by testing, ls|sort then redirects to out.txt

示例3:

Fill in the blank?  Can you have both a < and a > with a | ???

5 个答案:

答案 0 :(得分:22)

就句法分组而言,><具有更高的优先级;也就是说,这两个命令是等价的:

sort < names | head
( sort < names ) | head

这两个:

ls | sort > out.txt
ls | ( sort > out.txt )

但就顺序排序而言,首先执行|;所以,这个命令:

cat in.txt > out1.txt | cat > out2.txt

将填充out1.txt,而不是out2.txt,因为> out1.txt|后执行,因此取代 it(因此没有输出传递给cat > out2.txt)。

同样,这个命令:

cat < in1.txt | cat < in2.txt

将打印in2.txt,而不是in1.txt,因为< in2.txt |后执行,因此取代 it(所以没有输入来自cat < in1.txt)。

答案 1 :(得分:14)

来自man bash(与其他报价一样):

SHELL GRAMMAR
   Simple Commands
       A simple command is a sequence of optional variable assignments followed by
       blank-separated words and redirections, and terminated  by  a  control
       operator. The first word specifies the command to be executed, and is
       passed as argument zero.  The remaining words are passed as arguments
       to the invoked command.

       The return value of a simple command is its exit status, or 128+n if
       the command is terminated by signal n.

   Pipelines
       A pipeline is a sequence of one or more commands separated by one of
       the control operators | or |&.  The format for a pipeline is:

              [time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

换句话说,您可以为(简单)命令进行任意数量的重定向;您也可以将其用作管道的一部分。或者换句话说,重定向比管道绑定更紧密。

有几种方法可以解决这个问题(虽然它们很少是必要的或美学的):

1.你可以制作一个“复合命令”并重定向到它:

 Compound Commands
   A compound command is one of the following:

   (list)  list is executed in a subshell environment (see
           COMMAND EXECUTION ENVIRONMENT below).  Variable
           assignments  and  builtin  commands  that  affect  the
           shell's environment do not remain in effect after the
           command completes.  The return status is the exit status of list.

   { list; }
          list  is  simply  executed  in the current shell environment.  list
          must be terminated with a newline or semicolon.  This is known as a
          group command. The return status is the exit status of list.  Note
          that unlike the metacharacters ( and ), { and } are reserved words
          and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from
          list by whitespace or another shell metacharacter.

所以:

$ echo foo > input
$ { cat | sed 's/^/I saw a line: /'; } < input
I saw a line: foo

2.您可以使用“流程替换”重定向到管道:

Process Substitution
   Process  substitution  is  supported on systems that support named pipes
   (FIFOs) or the /dev/fd method of naming open files.  It takes the form of
   <(list) or >(list).  The process list is run with its input or output
   connected to a FIFO or some file in /dev/fd.  The name of this file is
   passed as  an  argument  to  the  current  command  as the result of the
   expansion.  If the >(list) form is used, writing to the file will provide
   input for list.  If the <(list) form is used, the file passed as an argument
   should be read to obtain the output of list.

所以:

 rici@...$ cat > >(sed 's/^/I saw a line: /') < <(echo foo; echo bar)
 I saw a line: foo
 rici@...$ I saw a line: bar

(为什么在输出终止之前会出现提示,如何将其作为练习留下来。)

答案 2 :(得分:3)

这几乎是我在阅读之后所理解的(包括ruakh的回答)

首先,如果多次重定向,则会执行所有重定向,但只有最后一次重定向才会生效(假设之前的重定向都不会导致错误)

  • e.g。 cat < in1.txt < in2.txt相当于cat < in2.txt,除非in1.txt不存在,否则此命令将失败(因为< in1.txt首先执行)

  • 同样,对于cat in.txt > out1.txt > out2.txt,只有out2.txt会包含out2.txt的内容,但由于> out1.txt首先执行,out1.txt将是如果它不存在则创建。

什么管道将前一个命令的stdout连接到下一个命令的stdin,并且该连接在任何其他重定向之前(来自Bash manual)。

所以你可以想到

cat in1.txt > out1.txt | cat > out2.txt

as

cat in1.txt > pipe > out1.txt; cat < pipe > out2.txt

应用前面提到的多重定向规则,我们可以将其简化为

cat in1.txt > out1.txt; cat < pipe > out2.txt

结果in1.txt的内容已复制到out1.txt,因为没有任何内容写入pipe

<小时/> 使用ruakh的另一个例子,

cat < in1.txt | cat > in2.txt

大致相当于

cat > pipe < in1.txt; cat < pipe < in2.txt

实际上是

cat > pipe < in1.txt; cat < in2.txt

结果:这次写入了pipe,但由于第二个catin2.txt而不是pipe读取,打印出in2.txt的内容。

答案 3 :(得分:3)

<放在任何你喜欢的位置,这有点非常规,但完全合法,所以我更喜欢这个,因为它更好地说明了从左到右的数据流:

<input.txt sort | head >output.txt

唯一不能执行此操作的是内置控制结构命令(forifwhile)。

# Unfortunately, NOT LEGAL
<input.txt  while read line; do ...; done

请注意,所有这些都是等效命令,但为了避免混淆,您应该只使用第一个或最后一个:

<input.txt grep -l foobar
grep <input.txt -l foobar
grep -l <input.txt foobar
grep -l foobar <input.txt

因为文件名必须始终直接在重定向操作符之后,所以我更愿意省略<和文件名之间的可选空格。

答案 4 :(得分:1)

更正:

示例1:

sort < names | head

在这种情况下,输入重定向首先运行(名称已排序),然后将其结果通过管道传送到头部。

一般情况下,您可以从左到右阅读。标准习语的工作原理如下:

  • 使用输入重定向“&lt;”告诉程序从文件中读取而不是stdin
  • 使用输出重定向“&gt;”告诉程序输出到文件而不是stdout
  • 使用管道“program_a | program_b”将通常由program_a输出的所有内容传递给stdout,并将其全部直接提供给program_b,就像从stdin中读取一样。