BASH技术问题:如何将标准输入重定向至数量可变的子进程
解决stdin重定向到可变数量子进程的问题
你遇到的核心问题是:bash在数组展开阶段不会重新解析进程替换(>())语法,所以直接把>>()放进数组再传给tee,这些内容只会被当作普通文件名或命令行参数,不会触发进程替换。
下面给两种可行的解决方案:
方案一:用eval强制解析进程替换(适合可控场景)
如果你的子进程命令都是自己可控的(无不可信输入),可以用eval让bash重新解析构造好的命令参数:
# 定义要执行的子进程命令(只存命令和参数,不用加>>()) programs=("exe_1 args_1" "exe_2 args_2" "exe_n args_n") # 构造tee的进程替换参数 tee_args=() for cmd in "${programs[@]}"; do tee_args+=(">($cmd)") done # 用eval执行,让bash解析进程替换 eval "tee ${tee_args[*]} >/dev/null"
⚠️ 注意:如果programs里的内容来自不可信输入,eval会有安全风险,可能被注入恶意代码,这种情况不要用这个方案。
方案二:用文件描述符管理子进程(更安全)
这种方法不需要eval,通过手动创建管道和管理文件描述符来实现,更安全:
# 定义子进程命令列表 programs=("exe_1 args_1" "exe_2 args_2") # 启动所有子进程,保存它们的输入管道文件描述符 pipes=() for cmd in "${programs[@]}"; do # 创建管道并启动子进程,将管道写入端的文件描述符存入数组 exec {fd}> >($cmd) pipes+=($fd) done # 读取stdin的每一行,写入所有子进程的管道 while IFS= read -r line; do for fd in "${pipes[@]}"; do echo "$line" >&$fd done done # 关闭所有管道,让子进程正常结束 for fd in "${pipes[@]}"; do exec {fd}>&- done
这个方法的好处是完全避免了eval的安全问题,而且能精准控制每一行输入的分发。
为什么原来的写法不行
bash的语法解析顺序是先处理进程替换、重定向这些特殊语法,再处理数组展开。所以你把>>()放进数组的时候,bash已经完成了语法解析,数组展开后这些内容只会被当作普通字符串传给tee,自然不会触发进程替换,还会把参数里的-开头内容当成tee的选项,导致错误。
内容的提问来源于stack exchange,提问作者Mega-X
相关产品推荐
相关产品推荐

