简体   繁体   English

从文件描述符读取的循环(在后台进程中)不退出

[英]While loop (in a background process) reading from file descriptor does not exit

I'll explain my problem statement first.我将首先解释我的问题陈述。 I have a command1 which generates data on both stderr and stdout, the stdout is piped to command2, while the stderr should go to a background process which continuously calls an API.我有一个command1,它在stderr和stdout上生成数据,stderr通过管道传输到command2,而stderr应该go到一个后台进程,该进程不断调用API。

Dummy example of the same:相同的虚拟示例:

#!/bin/bash

set -e;

metric_background_process () {
    # This while loop waits till there is a line to read
    while read -u 3 -r line; do
        echo $line;
    done;
    
    # This never prints !!!
    echo "Done"
}

tmp_dir=$(mktemp -d)
mkfifo "$tmp_dir/f1"

# Allocate a file descriptor to the named pipe
# to allow read and write from it.
exec 3<> "$tmp_dir/f1"

metric_background_process <&3 &
pid=$!


# Main commands (stdout is being piped to stderr as a dummy case)
cat ./assets/random_file 1>&3

exec 3<&-

wait $pid

The input file contains: 1 through 9, with 9 being the last line.输入文件包含:1 到 9,其中 9 是最后一行。

Observed Output:观察到 Output:

1
2
3
4
5
6
7
8

The shell waits after printing 8 , 9 is not printed, and the program does not stop by itself. shell 打印8后等待, 9不打印,程序不会自行停止。

No matter what I try, the while loop does not exit.无论我尝试什么, while循环都不会退出。 Maybe I'm missing something simple, any help or further questions for clarification would be highly appreciated.也许我错过了一些简单的东西,任何帮助或进一步的澄清问题将不胜感激。

The parent shell is opening the fifo for read/write ( <> ).父 shell 正在打开 fifo 以进行读/写 ( <> )。 The subshell ( & ) inherits the FD so it's also opening the fifo for read/write.子shell ( & ) 继承了 FD,因此它也打开了 fifo 以进行读/写。 When the parent closes the FD the subshell is still opening the fifo for writing so the write side is never closed and so the read side ( read -u 3 ) cannot get EOF .当父级关闭 FD 时,子外壳仍在打开 fifo 进行写入,因此写入端永远不会关闭,因此读取端( read -u 3 )无法获得EOF

To make it a bit simpler —为了让它更简单一点——

The script:剧本:

$ cat foo.sh 
metric_background_process () {
    local fifo=$1

    while read line; do
        echo $line
    done < $fifo
    
    echo "Done"
}

tmp_dir=$(mktemp -d)
fifo="$tmp_dir/f1"
mkfifo "$tmp_dir/f1"

metric_background_process $fifo &
pid=$!

exec 3> $fifo

for i in {1..5}; do
    echo i=$i >&3
done

exec 3>&-

wait $pid

Result:结果:

$ bash foo.sh
i=1
i=2
i=3
i=4
i=5
Done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM