【问题标题】:What does "< <(command args)" mean in the shell?shell 中的“< <(command args)”是什么意思?
【发布时间】:2025-12-06 21:20:02
【问题描述】:

当递归遍历包含空格的文件的文件夹时,我使用的 shell 脚本就是这种形式,从 internet 复制:

    while IFS= read -r -d $'\0' file; do
      dosomethingwith "$file"        # do something with each file
    done < <(find /bar -name *foo* -print0)

我想我理解 IFS 位,但我不明白“&lt; &lt;(...)”字符的含义。显然这里有某种管道。

谷歌“

【问题讨论】:

  • "man sh" 无论如何都是你的朋友。
  • 不是&lt; &lt;,而是&lt;&lt;(...) 运算符,如果我没记错的话
  • dosomething "$file" 绝对是误导。之所以使用这个结构是因为在原始页面中,一个数组在循环内被修改了
  • 感谢乔纳森编辑问题。意识到模式是“
  • 我认为,为了更好地理解和回忆,“进程替换”运算符应该称为企鹅运算符

标签: bash shell built-in


【解决方案1】:

&lt;() 在手册中称为process substitution,类似于管道,但传递/dev/fd/63 形式的参数,而不是使用标准输入。

&lt; 从命令行命名的文件中读取输入。

合起来,这两个操作符的作用就像一个管道,所以可以重写为

find /bar -name *foo* -print0 | while read line; do
  ...
done

【讨论】:

  • 不启动子shell就不一样了
  • +1 因为您有正确的符号名称。正如@knittl 指出的那样,它与您的重写并不完全相同,因为循环将在子外壳中运行,并且循环对变量所做的任何更改只会影响子外壳,而不是主脚本。您可以通过将 'find' 的输出重定向到 '{ while ...; do ...; done; ...rest of script...; }' 来处理这个问题,使用大括号将脚本的其余部分(循环和其他材料)组合到一个子 shell 中。
  • 谢谢。我可以感觉到我的头骨在执行 shell 脚本的大脑部分扩展。对谷歌有一个精确的术语会使它更容易。现在我要去看看什么是 subshel​​l。
【解决方案2】:

ls /usr/bin | more

或者这个:

more <( ls /usr/bin )

但不是这个:

more $( ls /usr/bin )

当您进一步调查时,原因会变得很清楚:

~$ echo $( ls /tmp )
gedit.maxtothemax.436748151 keyring-e0fuHW mintUpdate orbit-gdm orbit-maxtothemax plugtmp pulse-DE9F3Ei96ibD pulse-PKdhtXMmr18n ssh-wKHyBU1713 virtual-maxtothemax.yeF3Jo
~$ echo <( ls /tmp )
/dev/fd/63
~$ cat <( ls /tmp )
gedit.maxtothemax.436748151
keyring-e0fuHW
mintUpdate
orbit-gdm
orbit-maxtothemax
plugtmp
pulse-DE9F3Ei96ibD
pulse-PKdhtXMmr18n
ssh-wKHyBU1713
virtual-maxtothemax.yeF3Jo

/dev/fd/whatever 就像一个文本文件,括号之间是命令的输出。

【讨论】:

    【解决方案3】:

    &lt; 重定向到标准输入。

    &lt;() 似乎是某种反向管道,如页面所述:

    find /bar -name *foo* -print0 | \
    while IFS= read -r -d $'\0' file; do
      dosomethingwith "$file"        # do something with each file
    done
    

    不会工作,因为 while 循环将在子 shell 中执行,您将丢失在循环中所做的更改

    【讨论】:

    • 这个答案将受益于“过程替换”的外部参考和解释它的 URL,如 gnu.org/software/bash/manual/bashref.html#Process-Substitution。关键是子shell和对子shell中的变量所做的更改。另一种处理方式是:find ... | { while ...; do ...; done; ...rest of script...; },使用大括号在子 shell 中运行脚本的所有其余部分,而不仅仅是 while 循环。