unix 管|重定向< >优先级

5f0d552i  于 4个月前  发布在  Unix
关注(0)|答案(5)|浏览(68)

我想弄清楚:什么时候管道|或重定向<>在命令中优先?
这是我的想法,但我需要确认它是如何工作的。
例一:

sort < names | head

字符串
管道首先运行:names|head,然后对从names|head返回的内容进行排序
例二:

ls | sort > out.txt


这一个似乎直接通过测试,ls|sort然后重定向到out.txt
例三:
填空?你能同时拥有一个<和一个>和一个|吗???

vjrehmav

vjrehmav1#

在语法分组方面,><具有更高的优先级;也就是说,这两个命令是等效的:

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是在|之后执行的,因此 * 取代了 * 它(因此没有输出到cat > out2.txt)。
类似地,此命令:

cat < in1.txt | cat < in2.txt


将打印in2.txt,而不是in1.txt,因为< in2.txt是在|之后执行的,因此会 * 取代它(因此不会从cat < in1.txt输入)。

798qvoo8

798qvoo82#

来自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


(Why在输出终止之前出现提示,以及如何处理它作为练习)。

93ze6v8z

93ze6v8z3#

这差不多是我在做了一些阅读(包括ruakh的回答)后所理解的
首先,如果你重定向多次,所有的重定向都会被执行,但只有最后一次重定向会生效(假设之前的重定向都没有导致错误)

  • 例如,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不存在,则会创建out1.txt

pipe所做的是将上一个命令的stdout连接到下一个命令的stdin,并且该连接在任何其他重定向之前(来自Bash手册)。
所以你可以想到

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

字符串
作为

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][3]的另一个例子,

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的内容被打印出来。如果pipe在同一侧(><)重定向的中间,它将被ingorr。

ahy6op9u

ahy6op9u4#

<放在任何你喜欢的地方有点不正统,但完全法律的,所以我更喜欢这样,因为它更好地说明了从左到右的数据流:

<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


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

egmofgnx

egmofgnx5#

更正:
例一:

sort < names | head

字符串
在这种情况下,输入重定向首先运行(名称被排序),然后将结果通过管道传输到head。
一般来说,你可以从左到右阅读。标准的习惯用法如下:

  • 使用输入重定向“<”告诉程序从文件而不是标准输入中读取
  • 使用输出重定向“>”告诉程序输出到文件而不是标准输出
  • 管道的使用“程序_a| program_B”将program_a通常输出到标准输出的所有内容直接输入到program_B,就像从标准输入中读取一样。

相关问题