如何实现流式Shell命令执行器,使命令捕获自身标准输入?
Shell脚本行为差异与命令流执行器实现
两种脚本的行为差异
1. 嵌套sh的here-doc脚本(script.sh)
脚本代码:
#!/bin/sh sh <<EOF cat | xargs -n 1 echo captured echo first echo second EOF
执行后,cat会捕获here-doc内的后续命令流而非外部输入,输出如下:
captured echo captured first captured echo captured second
即使通过echo input | script.sh调用,结果完全一致。
2. 普通脚本(script-plain.sh)
脚本代码:
#!/bin/sh cat | xargs -n 1 echo captured echo first echo second
执行echo input | script-plain.sh时,cat会读取外部传入的stdin,输出如下:
input first second
需求说明
需实现executor.sh,通过curl some-streaming-endpoint获取持续输出的命令流(示例内容:echo ping 1、cat、echo ping 2...echo ping n),满足以下要求:
- 命令流中的
echo命令正常执行并输出对应内容; - 命令流中的
cat命令捕获executor.sh的外部stdin(如echo "data 1\ndata 2"传入的内容); - 禁止使用临时文件存储命令流(因流为持续输出)。
执行echo "data 1\ndata 2" | ./executor.sh需输出:
ping 1 data 1 data 2 ping 2 ping 3 ... ping n
实现方案
以下是executor.sh的代码:
#!/bin/sh # 将外部stdin复制到文件描述符3保存 exec 3<&0 # 持续读取命令流并逐行处理 curl some-streaming-endpoint | while read -r cmd; do case "$cmd" in cat) # cat命令从保存的外部stdin读取内容 cat <&3 ;; *) # 其他命令直接执行 eval "$cmd" ;; esac done # 关闭文件描述符3 exec 3<&-
代码说明
- 保存外部输入:通过
exec 3<&0把外部传入的stdin复制到文件描述符3,避免命令流占用主stdin后无法读取外部输入; - 流式处理命令:用
while read -r cmd逐行读取curl返回的持续命令流,无需缓存全部内容; - 命令分支处理:
- 遇到
cat时,直接从文件描述符3读取外部输入并输出,确保符合需求; - 其他命令通过
eval执行,保证echo等命令正常输出内容。
- 遇到
内容的提问来源于stack exchange,提问作者404
相关产品推荐
相关产品推荐

