exec 如何与 shell 中的管道交互?

exec 如何与 shell 中的管道交互?

假设我的代码开头有以下内容:

exec < file

如果我理解正确的话,这意味着所有尝试从 stdin 读取的命令实际上都会从 读取file

但是如果我有cmd1 | cmd2cmd2将从cmd1的输出中读取还是file

答案1

如果我理解正确的话,这意味着所有试图从 stdin 读取的命令实际上都会从文件中读取

如果满足以下条件,则从其标准输入读取的命令将从常规文件读取:它是stdin 恰好是一个常规文件。从其 stdin 读取的命令将从终端或 fifo(也是文件) 如果它是stdin 恰好分别是一个终端或 fifo。

一个命令的标准输入可以与另一个命令的标准输入不同。

在由 解释的脚本中bash,仅exec < file重定向此特定进程的标准输入bash。如果后续命令继承了标准输入,则它们将受到影响,但无论您是否使用,继承都以相同的方式发生exec < file

如果你运行它cmd0,它将从解释器继承 stdin 和 stdout (和 stderr) bash。解释器的 stdin 和 stdoutbash是什么并不重要;机制始终相同。

如果你运行,cmd1 | cmd2 | … | cmdN那么cmd1将从解释中继承 stdin bash,并cmdN从解释中继承 stdout bash。其他 stdin 和 stdouts 将形成一个管道(的 stdoutcmd1连接到的 stdincmd2等等)。解释的 stdin 和 stdout 是什么并不重要bash;机制始终相同。

您使用的事实exec < file与机制本身无关。某些命令将从解释器继承 stdin 和/或 stdout bash。如果没有,exec < file它们将继承某物他们exec < file将继承其他东西作为标准输入。

这意味着exec < file可以影响某些命令,但仅限于从解释器继承 stdin 的命令bash。您的cmd1确实继承了解释器的 stdin bash,但cmd2没有。

假设您cmd2只是从其 stdin 读取,它将从 的输出中读取cmd1。 前者exec < file并不重要。 (请注意,通常cmd2可能会重定向、忽略或关闭其 stdin;设计用于管道的命令不会这样做,除非被告知。)

您可以在脚本中测试这一点:

#!/bin/bash
# Don't run this in an interactive shell. Run as a script.
exec < /etc/fstab
echo foo | cat
wc -l

请注意,如果您将上述代码粘贴到交互式环境中,bash那么您将更改其自身的 stdin bash,并且它最终将在 EOF 时退出。为方便起见,下面是一个可以在交互式 shell 中运行而不终止它的版本:

bash -c '
   exec < /etc/fstab
   echo foo | cat
   wc -l
'

输出应为foo(证明cat读取的输出),后跟一个数字,表示(证明读取自)echo中的行数。fstabwcfstab

相关内容