bash 中的 <() 到底是什么(zsh 中的 =() )?

Hen*_*los 67 linux bash zsh shell

我对 bash 很满意,但最近我换了一个我不知道的替代品。

<(command)bash究竟是什么?它与=(command)zsh中的相比如何?

我知道这与默认文件描述符有关。在我的电脑里

echo <()
Run Code Online (Sandbox Code Playgroud)

Returns /proc/self/fd/11,我发现它是脚本 STDOUT 的副本,但这对我来说似乎仍然很混乱。

Ada*_*hon 93

这称为进程替换。

<(list)语法由两个支持,bashzsh。它提供了一种在无法list使用管道 ( |)时将命令 ( )的输出传递给另一个命令的方法。例如,当一个命令不支持输入STDIN或您需要多个命令的输出时:

diff <(ls dirA) <(ls dirB)
Run Code Online (Sandbox Code Playgroud)

<(list)将 的输出list与 中的文件连接/dev/fd,如果系统支持,否则使用命名管道(FIFO)(这也取决于系统的支持;这两个手册都没有说明如果不支持这两种机制会发生什么,大概它会中止一个错误)。然后将文件名作为参数传递到命令行。


zsh另外支持=(list)尽可能替换<(list). 使用=(list)临时文件代替文件输入/dev/fd或先进先出。<(list)如果程序需要在输出中查找,它可以用作替代。

根据ZSH 手册,工作方式可能还存在其他问题<(list)

=表单很有用,因为/dev/fd和 的命名管道实现<(...)都有缺点。在前一种情况下,某些程序可能会在检查命令行上的文件之前自动关闭有问题的文件描述符,尤其是出于安全原因(例如程序运行 setuid 时)需要这样做时。在第二种情况下,如果程序实际上没有打开文件,则尝试从管道中读取或写入的子 shell 将永远阻塞(在典型的实现中,不同的操作系统可能有不同的行为)并且必须明确地杀死. 在这两种情况下,shell 实际上都使用管道提供信息,因此希望lseek(2)在文件上lseek(参见手册页)的程序将无法运行。


gle*_*man 19

请注意,这是一个 bash 答案,而不是 zsh。

在 bash 中有些情况你不能使用管道:

some_command | some_other_command
Run Code Online (Sandbox Code Playgroud)

因为管道为管道的每个组件引入了子壳,当子壳退出时,您依赖的任何副作用都会消失。例如,这个人为的例子:

cat file | while read line; do ((count++)); done
echo $count
Run Code Online (Sandbox Code Playgroud)

将显示一个空行,因为该$count变量在当前 shell 中不存在。

bash进程替换允许您像从文件中一样读取“some_command”输出,从而避免这个难题

while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count   # the variable *does* exist in the current shell
Run Code Online (Sandbox Code Playgroud)

(1) 是正常的输入重定向。(2) 是<()进程替换语法的开始。

  • zsh 中的 =(cmdlist) 与 bash 中的 &lt;(cmdlist) 效果几乎相同,但它会创建(并在准备好时删除)一个临时文件,其中包含用于重定向的 cmdlist 输出。当在程序中可能完成查找时,这很好。&lt;(cmdlist) 也被 zsh 知道。 (2认同)