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

Mat*_*hid 5 shell bash

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

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

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

command1 && command2 >file
Run Code Online (Sandbox Code Playgroud)

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

command1 | command2 && command3 | command4
Run Code Online (Sandbox Code Playgroud)

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

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

Kus*_*nda 7

在命令中

command1 && command2 >file
Run Code Online (Sandbox Code Playgroud)

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

$ echo hello && echo ok >file
hello
$ cat file
ok
Run Code Online (Sandbox Code Playgroud)

重定向command1可以单独完成:

command1 >file1 && command2 >file2
Run Code Online (Sandbox Code Playgroud)

在命令中

command1 | command2 && command3 | command4
Run Code Online (Sandbox Code Playgroud)

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

$ echo hello | cat && echo bye | cat
hello
bye
Run Code Online (Sandbox Code Playgroud)

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

command1 | { command2 && command3; } | command4
Run Code Online (Sandbox Code Playgroud)

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

$ echo hello | { read message && printf 'We got "%s"\n' "$message"; } | rev
"olleh" tog eW
Run Code Online (Sandbox Code Playgroud)

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

$ echo hello | { read message && printf 'We got "%s"\n' "$message"; echo bye >&2; } | rev
bye
"olleh" tog eW
Run Code Online (Sandbox Code Playgroud)

在 shell 语法中,“完整命令”由以&&或分隔的管道列表组成||。这是非常松散的说法。这意味着&&||将比|管道中的具有更高的优先级。

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

显然,“复合命令”也可以重定向。复合命令是{ ...; }大括号组或( ... )子shell 中的管道(可能是单个简单命令),或者是if, while, for, until, 或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
Run Code Online (Sandbox Code Playgroud)

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