重定向如何与命令列表交互?

重定向如何与命令列表交互?

大多数人都知道,shell 允许您在运行命令时重定向 stdin/stdout/stderr,还可以将输出从一个命令传输到另一个命令。

可能很少有人知道,您可以使用运算符编写有条件或无条件地依次执行的“列表”命令; && ||

这些功能如何相互作用?如果我做类似的事情

command1 && command2 >file

它是仅重定向最后一个命令的输出,还是两者都重定向?如果我写

command1 | command2 && command3 | command4

它实际上是做什么的?这是两个带有条件的管道吗?或者这是一条管道包含条件作为管道的步骤之一?

据我所知,shell 不支持添加括号来消除歧义,所以我不确定您如何请求一种解释或另一种解释......无论如何,了解 shell 如何解释会很有用所有这些。 (像大多数人一样,我只使用 Bash。)

答案1

在命令中

command1 && command2 >file

的输出command1未重定向,但 的输出command2是:

$ echo hello && echo ok >file
hello
$ cat file
ok

重定向command1可以单独完成:

command1 >file1 && command2 >file2

在命令中

command1 | command2 && command3 | command4

的输出command1通过管道传输到command2.如果第一个管道以零退出状态终止,则第二个管道将以类似的方式运行:

$ echo hello | cat && echo bye | cat
hello
bye

如果command2 && command3要对列表进行分组,则将其写为

command1 | { command2 && command3; } | command4

这意味着 的输出通过command1管道传送到复合命令command2 && command3。然后复合命令的输出通过管道传输到command4

$ echo hello | { read message && printf 'We got "%s"\n' "$message"; } | rev
"olleh" tog eW

单个简单命令(见下文)可以被重定向:

$ echo hello | { read message && printf 'We got "%s"\n' "$message"; echo bye >&2; } | rev
bye
"olleh" tog eW

&&在 shell 语法中,“完整命令”由一系列由或分隔的管道组成||。这是非常宽松请讲。这意味着&&和在管道中的||优先级高于。|

另一方面,重定向与当前命令紧密结合,因为语法使重定向成为“简单命令”构造的一部分。一个简单的命令是一些命令前缀、命令名称和命令后缀(其中前缀和后缀是可选的)。命令前缀可以是对环境变量的赋值 ( VAR=value myscript),也可以是重定向 ( >outfile cat)。同样,命令后缀可以是重定向 ( cat >outfile) 等。

显然,“复合命令”也可以重定向。复合命令是{ ...; }大括号组中或子 shell 中的管道(可能是单个简单命令) ,( ... )或者是ifwhileforuntil、 或case语句。

POSIX shell(其bash扩展)的完整语法可在 POSIX 标准中找到。以下只是语法规则的顶层:

program          : linebreak complete_commands linebreak
                 | linebreak
                 ;
complete_commands: complete_commands newline_list complete_command
                 |                                complete_command
                 ;
complete_command : list separator_op
                 | list
                 ;
list             : list separator_op and_or
                 |                   and_or
                 ;
and_or           :                         pipeline
                 | and_or AND_IF linebreak pipeline
                 | and_or OR_IF  linebreak pipeline
                 ;
pipeline         :      pipe_sequence
                 | Bang pipe_sequence
                 ;
pipe_sequence    :                             command
                 | pipe_sequence '|' linebreak command

(参考:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02

相关内容