PAYATHON 2026

Bash 中的 `command < <(command)` 是什么意思?

技术老齐

command1 < <(command2) 把 command2 的标准输出接到 command1 的标准输入。

下面这条命令会把 yq 的输出按行读入 Bash 数组 actions:

readarray actions < <(yq '.coolActions[]' sample.yaml)

这里组合了两种语法:单独的 < 是输入重定向,<(...) 是进程替换(process substitution)。

<:指定标准输入的来源

从文件读取数据时,可以这样写:

readarray actions < actions.txt

< actions.txt 让 readarray 从文件读取,不再等待终端输入。这里重定向的是标准输入,也就是文件描述符 0。

原命令中的第一个 < 起同样的作用,只是右侧换成了进程替换:

readarray actions < <(...)

<(...):提供读取命令输出的路径

Bash 遇到下面的表达式时,会异步运行括号内的命令,并提供一个可读取其标准输出的文件名:

<(yq '.coolActions[]' sample.yaml)

在使用 /dev/fd 的系统上,这个文件名可能形如 /dev/fd/63,具体编号不固定;其他环境可能使用命名管道。

整条命令可以理解为:

readarray actions < 某个连接到yq输出的路径

Bash 无须先把全部输出保存成普通磁盘文件。yq 产生数据时,readarray 就可以读取。

写法上有两点要注意:

  • <( 必须连在一起,不能写成 < (。
  • 外层的 < 与 <(...) 要分开;写成 << 会涉及 here-document 的语法。

示例命令如何得到数组

假设所用的 yq 支持这个表达式,并逐行输出以下字符串:

create
edit
delete

整条命令的数据流是:

sample.yaml → yq 的标准输出 → readarray 的标准输入 → actions 数组

.coolActions[] 取出 coolActions 序列中的各个元素。readarray 是 Bash 内建命令,也叫 mapfile,默认将每一行保存为一个数组元素,下标从 0 开始。

readarray 默认会保留每行末尾的换行符。假设上述三行都以换行符结尾,数组内容相当于:

actions=($'create\n' $'edit\n' $'delete\n')

如果需要去掉行尾的换行符,可以加上 -t:

readarray -t actions < <(yq '.coolActions[]' sample.yaml)

此时数组内容相当于:

actions=('create' 'edit' 'delete')

读取和遍历数组:

printf '%s\n' "${actions[0]}"
# create

for action in "${actions[@]}"; do
    printf 'action: %s\n' "$action"
done

循环输出为:

action: create
action: edit
action: delete

"${actions[@]}" 外面的双引号要保留,这样每个数组元素中的空格和通配符字符才能原样传递。

为什么不用管道

下面的写法也会把 yq 的输出传给 readarray:

yq '.coolActions[]' sample.yaml | readarray -t actions

但在 Bash 的默认行为下,管道里的 readarray 会在子 shell 中执行。数组赋值发生在子 shell 中,管道结束后,当前 shell 中的 actions 不会得到这次赋值。启用 lastpipe 且满足其条件时,行为可能不同。

使用进程替换时:

readarray -t actions < <(yq '.coolActions[]' sample.yaml)

readarray 在当前 shell 中执行,后续命令可以直接访问 actions。

使用时还要注意什么

  • 需要使用提供 readarray 的 Bash 环境。readarray 和 <(...) 都不属于 POSIX sh 的通用语法,不应直接用 sh script.sh 执行这类脚本。
  • 名为 yq 的工具有不同实现,表达式和输出选项可能不同。示例以它能输出上述三行为前提;数组实际接收到的内容取决于 yq 的标准输出。
  • readarray -t 按行拆分数据。如果某个 YAML 字符串本身包含换行符,就不能再假定“一个 YAML 元素对应一个数组元素”。
  • 这条命令结束后的 $? 是 readarray 的退出状态,不能直接用它判断进程替换中的 yq 是否成功。

备注:内容仅供参考。