如何读取后台子shell生成的管道输出?Shell脚本问题求助
Shell脚本后台进程输出捕获异常的问题解决
问题场景
编写Shell脚本时,尝试通过while-read循环捕获多个后台进程的输出,但subscribe_audio_v1函数无法正常工作,subscribe_audio_v2却能正常运行。最初推测是管道子shell导致,实际是缓冲机制差异。精简后的脚本如下:
#!/bin/sh # 无法正常工作的版本 function subscribe_audio_v1() { pactl subscribe | awk '/change/{print "event_audio_v1"}' } # 可以正常工作的版本 function subscribe_audio_v2() { pactl subscribe | while read -r x do case "$x" in *change*) echo event_audio_v2 ;; esac done } function event_container() { subscribe_audio_v1 & subscribe_audio_v2 & } function loop() { while read -r x do case $x in event_audio*) echo "Working on ${x}..." ;; esac done } event_container | loop
编辑补充:尝试通过新文件描述符规避全缓冲,虽然两个函数都能输出字符串,但无法将输出捕获为loop函数的输入:
exec 3>&1 event_container >&3 loop <&3
问题原因
subscribe_audio_v1失效的核心原因:awk的全缓冲机制
默认情况下,当awk的输出指向管道时,会启用全缓冲——只有当输出缓冲区被填满(通常为4KB或8KB)时,才会将内容刷到管道中。而pactl subscribe的事件输出频率低,缓冲区无法被填满,导致输出一直被积压,loop无法收到任何内容。subscribe_audio_v2正常的原因:行缓冲机制while read -r x是逐行读取输入,echo命令的输出默认是行缓冲——每输出一行就会立即刷新到管道,所以loop能实时收到事件。- 文件描述符方法的问题
exec 3>&1是将文件描述符3重定向到当前终端的标准输出,event_container >&3会把后台进程的输出直接打印到终端,而非写入到loop的输入流中,因此loop <&3无法读到任何内容。
解决方法
方法1:强制awk使用行缓冲
通过在awk中手动刷新输出缓冲区,或使用参数强制行缓冲:
- 方法1a:在awk的print后添加
fflush(stdout)(POSIX兼容):function subscribe_audio_v1() { pactl subscribe | awk '/change/{print "event_audio_v1"; fflush(stdout)}' } - 方法1b:使用
stdbuf命令强制awk输出为行缓冲(GNU环境):function subscribe_audio_v1() { pactl subscribe | stdbuf -oL awk '/change/{print "event_audio_v1"}' }
方法2:使用命名管道统一收集后台进程输出
如果需要更灵活的输出收集,可以用命名管道(FIFO)来传递后台进程的输出:
#!/bin/sh # 创建命名管道 mkfifo event_pipe function subscribe_audio_v1() { pactl subscribe | awk '/change/{print "event_audio_v1"; fflush(stdout)}' } function subscribe_audio_v2() { pactl subscribe | while read -r x do case "$x" in *change*) echo event_audio_v2 ;; esac done } function event_container() { subscribe_audio_v1 > event_pipe & subscribe_audio_v2 > event_pipe & } function loop() { while read -r x do case $x in event_audio*) echo "Working on ${x}..." ;; esac done } # 启动事件收集和处理 event_container loop < event_pipe # 清理命名管道 rm event_pipe
内容的提问来源于stack exchange,提问作者decepticlown
相关产品推荐
相关产品推荐

