Erlang: How to pipe stdin input from a file to an erlang program and match eof?

社会主义新天地 提交于 2019-12-06 07:56:46

问题


How to pipe input from a file as stdin to an erlang program running in the shell as well as standalone?

I have a file hr.erl and I compile it from the shell. There is a function in it which accepts input from stdin using io:fread(). I have written a case expression with guards where if it matches {ok, [0]} it should terminate. Instead of 0, I actually need it to be eof.

  1. How to send eof when running in a shell?
  2. I have a file inp.txt with values 1 2 3 and 0 on each line. How can I pass it using the < pipe operator? Is there anything like erl -hr <inp.txt? Can I pipe it to stdin within the shell.

Here is my program so far (updated to include eof).

-module(hr).
-export([main/0]).    

r(L) ->
    case io:fread("", "~d") of
        eof -> 
            io:format("eof~n", []),
            ok;
        {ok, [0]} ->
            io:format("terminate~n", []),
            lists:reverse(L);
        {ok, [N]} ->
            io:format("inp ~p~n", [N]),
            r([N|L])
    end.

main() -> r([]).

From shell

1> c(hr).
{ok,hr}
2> hr:main().
1
inp 1
2
inp 2
3
inp 3
0
terminate
[1,2,3]

Thanks.


回答1:


This is one of the Erlang FAQs:

http://www.erlang.org/faq/how_do_i.html#id49435




回答2:


Look here for the fastest line oriented IO for Erlang known to me. Note the usage of -noshell and -noinput command line parameters. Key part is

read() ->
   Port = open_port({fd, 0, 1}, [in, binary, {line, 256}]),
   read(Port, 0, [], []).

read(Port, Size, Seg, R) ->
  receive
    {Port, {data, {eol, <<$>:8, _/binary>> = Line}}} ->
      read(Port, Size + size(Line) + 1, [],
        [iolist_to_binary(lists:reverse(Seg, [])) | R]);
    {Port, {data, {eol, Line}}} ->
      read(Port, Size + size(Line) + 1, [Line | Seg], R);
    {'EXIT', Port, normal} ->
      {Size, [list_to_binary(lists:reverse(Seg, [])) | R]};
    Other ->
      io:format(">>>>>>> Wrong! ~p~n", [Other]),
      exit(bad_data)
  end.

EDIT: Note that the line oriented IO was fixed in R16B http://erlang.org/pipermail/erlang-questions/2013-February/072531.html so you need this trick no longer.

EDIT2: There is an answer using fixed file:read_line/1.




回答3:


I am able to pipe input when using escript. Write the erlang program without module or export info, with main(_) function, i.e., in escript compatible way. Then we can pipe input using cat like

cat inp.txt | escript hr.erl

This works and program terminates when it encounters eof. But I still don't know why it's not working when using redirect operator <.



来源:https://stackoverflow.com/questions/19642198/erlang-how-to-pipe-stdin-input-from-a-file-to-an-erlang-program-and-match-eof

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!