寻找不会触发EOF的文件替代mkfifo命名管道,实现输出行前缀添加
解决命名管道触发EOF导致处理进程退出的问题
你的核心问题在于:命名管道(FIFO)在所有写端被关闭时会向读端发送EOF,所以当你的脚本执行完所有echo命令并退出后,打开的文件描述符3被关闭,cat进程收到EOF就会退出。
要实现“持续为输出行添加前缀”的需求,有几种比单纯FIFO更可靠的方案,或者可以改进FIFO的使用方式:
方案1:保持FIFO的写端始终打开
最简单的改进就是让FIFO至少有一个写端持续处于打开状态,这样读端就永远不会收到EOF。修改你的脚本如下:
# 创建FIFO mkfifo mypipe # 以读写模式打开FIFO,这个文件描述符3会一直保持到脚本退出 exec 3<>mypipe # 后台启动处理进程,从FIFO读取内容并添加前缀 while read line; do echo " [prepend] $line" done <&3 & # 随时发送内容到FIFO,处理进程会实时处理 echo "foo" >&3 echo "bar" >&3 echo "baz" >&3 # 如果需要脚本持续运行(比如等待后续输入),可以添加阻塞逻辑 # 比如等待用户输入,或者无限循环 read -p "Press Enter to stop processing..." # 手动关闭文件描述符(可选,脚本退出时会自动关闭) exec 3>&-
原理:exec 3<>mypipe同时打开了FIFO的读端和写端,只要这个文件描述符不被关闭,FIFO就始终存在一个活跃的写端,读端的while read(或者cat)就会一直等待新内容,不会因为EOF退出。
方案2:使用Unix域套接字替代FIFO
Unix域套接字是比FIFO更灵活的IPC方式,它不会在单端关闭时触发EOF,只有当连接完全断开时才会终止读取。可以用socat工具来实现:
# 后台启动套接字监听进程,收到内容后添加前缀输出 socat UNIX-LISTEN:/tmp/my_socket,fork EXEC:'while read line; do echo " [prepend] $line"; done' & # 发送内容到套接字 echo "foo" | socat UNIX-CONNECT:/tmp/my_socket - echo "bar" | socat UNIX-CONNECT:/tmp/my_socket - # 如果需要持续发送,可以保持连接打开 socat UNIX-CONNECT:/tmp/my_socket - & exec 3>&1 echo "baz" >&3
这种方式适合需要多客户端连接,或者更复杂的IPC场景,缺点是需要安装socat(大部分Linux发行版默认包含)。
方案3:用tail -f读取FIFO
tail -f命令的特性是即使文件(包括FIFO)的当前写端关闭,它也会持续监听文件的变化,等待新的写端打开。这样可以避免EOF导致的退出:
mkfifo mypipe # 用tail -f读取FIFO,后台运行处理逻辑 stdbuf -i0 -o0 tail -f mypipe | while read line; do echo " [prepend] $line"; done & # 发送内容,即使发送完后关闭写端,tail -f仍然会继续运行 echo "foo" > mypipe echo "bar" > mypipe # 后续可以随时再次打开FIFO写端发送内容,处理进程会继续处理 echo "new content" > mypipe
注意:添加stdbuf -i0 -o0是为了关闭缓冲,确保输出能实时显示,避免出现延迟。
内容的提问来源于stack exchange,提问作者user5047085
相关产品推荐
相关产品推荐

