Erlang如何无提示循环读取标准输入(管道输入场景)
解决Erlang程序从管道定时读取stdin的问题
首先,你提到的Erlang IO模块里带prompt()的函数都是为交互式输入设计的,在管道这种非交互式场景下并不适用。要实现每X毫秒循环读取stdin的逻辑,我们需要用非阻塞文件操作配合超时等待来实现,避免程序因为没有输入而一直阻塞。
下面是完整的实现方案:
核心思路
- 以
raw和nonblock模式打开标准输入,禁用缓冲并允许非阻塞读取,这样能实时获取管道传来的数据,不会因为缓冲导致延迟。 - 使用
file:select/3监听标准输入的可读事件,设置超时时间为X毫秒——有数据时立即读取处理,超时则继续循环,正好满足你每X毫秒轮询的需求。
完整代码示例
-module(pipe_reader). -export([start/1, loop/2]). % X是你需要的循环间隔(毫秒) start(X) -> % 打开标准输入,raw模式禁用缓冲,nonblock允许非阻塞读取 case file:open("/dev/stdin", [binary, read, raw, nonblock]) of {ok, StdIn} -> loop(StdIn, X); {error, Reason} -> io:format("Failed to open stdin: ~p~n", [Reason]), error end. loop(StdIn, X) -> % 等待stdin可读,超时X毫秒 case file:select([StdIn], [], [], X) of {[StdIn], [], []} -> % 有数据可读,读取最多1024字节(可根据需求调整) case file:read(StdIn, 1024) of {ok, NewMsg} -> do_something(NewMsg), loop(StdIn, X); eof -> % 管道另一端的程序已退出,关闭stdin并结束循环 io:format("Input stream closed~n"), file:close(StdIn), ok; {error, Reason} -> io:format("Read error: ~p~n", [Reason]), file:close(StdIn), ok end; {[], [], []} -> % 超时,继续下一轮循环 loop(StdIn, X); {error, Reason} -> io:format("Select error: ~p~n", [Reason]), file:close(StdIn), ok end. % 替换成你自己的业务逻辑 do_something(Msg) -> io:format("Received: ~p~n", [Msg]).
关键细节说明
raw模式:禁用标准输入的行缓冲/全缓冲,确保管道中传来的数据能被立即读取,而不是等待缓冲区填满或换行符。nonblock模式:让file:read/2在没有数据时立即返回eagain,而不是阻塞程序。file:select/3:这是实现定时轮询的核心,它会等待指定的文件描述符变为可读,超时时间设为X毫秒,完美匹配你的需求。
使用方式
编译这个模块后,启动程序时将程序A的stdout通过管道传入:
./program_a | erl -noshell -eval 'pipe_reader:start(1000).'
上面的例子中,每1000毫秒(1秒)轮询一次stdin。
内容的提问来源于stack exchange,提问作者InDaPond
相关产品推荐
相关产品推荐

