Here is a simple program that uses the Unix module to interact with a subprocess. I just launch a cat shell command, send it a string and read it back:
#load "unix.cma";; (* Needed if you are in the toplevel *)
let () =
let sin, sout, serr = Unix.open_process_full "cat" [||] in
output_string sout "test\n";
flush sout;
input_line sin |> print_string;
flush stdout;
Unix.close_process_full (sin, sout, serr) |> ignore;;
Recently I started studying the Lwt library, and I wanted to reproduce the same functionality with it. I though that the following should have exactly the same result:
#use "topfind";; (* *)
#thread;; (* Also only for the toplevel *)
#require "lwt.simple-top";; (* *)
let () =
let open Lwt in
let process = Lwt_process.open_process_full ( "cat" , [||] ) in
Lwt_io.write_line process#stdin "test\n"
>>= ( fun () -> Lwt_io.flush process#stdin )
>>= ( fun () -> Lwt_io.read process#stdout )
>>= ( fun str -> Lwt_io.print str )
>>= ( fun () -> Lwt_io.flush Lwt_io.stdout )
|> Lwt_main.run
But it doesn't work as I expect it to -- apparently it reads and then prints an empty string.
I guess I have some fundamental confusion on how Lwt should work, but I cannot figure it out. Can someone show me how one can communicate with a subprocess using Lwt?
Use Lwt_process.shell to make a proper command, in your case, the proper command is the following:
Lwt_process.shell "cat";;
- : Lwt_process.command = ("", [|"/bin/sh"; "-c"; "cat"|])
Also, I suspect, that after you will run your program in a proper way, you will be wondering, why is your program blocking. This reason is because cat process will not finish until you write an EOF to it's input channel. That's why the Lwt_io.read call will not ever finish. A solution would be to close the stdin channel.
Related
I'm currently learning Lua and also learning how to work with CMD.
I know how to change a directory path and run my codes and files from that path
but what I don't know and I'm here to ask for is how to get out of a programming language REPL when you start it in CMD
For example to jump into the Lua REPL you should type:
lua53 (--like python3 for the Python language)
then you changed the CMD environment to a Lua compiler and can't access CMD commands such as
dir, cd, cls etc. and everytime when I need to access these commands I have to close the CMD window and open a new one.
Now can you guys tell me am I able to access CMD commands while in the Lua REPL? Or do I have to exit Lua first, and is there any command to exit a REPL?
I'd recommend EOF (Ctrl + D on Unix) rather than SIGKILL (Ctrl + C) because some REPLs (node and python) choose to ignore the latter (perhaps because it's often used for copying text?); python will just print KeyboardInterrupt whereas node will only exit if you press Ctrl + C twice (it will send a message telling you this the first time).
EOF (Ctrl + D) on the other hand immediately exists all REPLs I have used so far.
The Lua REPL stops immediately when it receives either EOF or SIGKILL, so you can use both here.
Edit: As Sowban points out, EOF apparently is entered as Ctrl + Z then Enter in powershell.
You could type ctrl c to exit the process that's running generally.
I suggest to write a REPL by yourself.
But be warned :-)
The main loop with a prompt and the interpreting and executing function/method is mostly the easiest part.
99.99999% is the errorhandling thing.
One of my earliest interpreter language is (A)REXX.
A REPL without any errorhandling is done with...
/* REXX have to start with a comment */
do forever
parse pull input
interpret input
end
Now Lua sandboxed to an _ENV with io and os library and a little bit of errorhandling...
#!/usr/bin/env -S readline-editor /usr/local/bin/lua
-- ^--SHEBANG for Linux --------------------------------------------------------------------------------------
-- interpreter.lua
-- Sandboxed to io and os
-- Lua 5.4 >>-because-> goto label <const> load()
--------------------------------------------------------------------------------------------------------------
local Lua = function(...)
-- Info about OS
io.write(("%s\n"):format(io.popen('uname -a'):read())):flush()
-- Global Setting
debug.setmetatable((1), {__index = math}) -- Add math library to number as methods (like string for strings)
os.setlocale('de_DE.UTF8')
os.setlocale('en_US.UTF8', 'time')
io.write(os.date("[%c]\n" .. ("%s\n"):format(os.setlocale():gsub("%;", "\n")))):flush()
-- io.write(("%s\n"):format(_VERSION)):flush()
-- Label for goto
::lua::
-- Local Setting
local args <const> = args or {...}
local Lua = Lua or true
local cmd = cmd or ""
--------------------------------------------------------------------------------------------------------------
local env <const> = env or setmetatable({os = os, io = io}, -- The _ENV for load()
{__call = function(self, ...)
local self, t = ({...})[1] or self, "" -- First argument becomes self if one
if ({...})[1] == "help" then self = getmetatable(({...})[2]).__index end -- Showing metamethod __index (table)
for k, v in pairs(self) do
t = t .. ("%s => %s\n"):format(k, v)
end
return t
end,
__index = {cg = collectgarbage,
gt = getmetatable,
pairs = pairs,
tn = tonumber,
ts = tostring,
_V = ("%s \27[1;" .. (31):random(36) .. "m(sandboxed)\27[0m"):format(_VERSION)},
__tostring = function(self) return self._V end}) -- end env
--------------------------------------------------------------------------------------------------------------
local prompt = prompt or setmetatable({}, {__tostring = function() return getmetatable(env).__index._V .. "> " end})
local name <const> = name or _VERSION
local result = result or true
--------------------------------------------------------------------------------------------------------------
while Lua do
io.write(tostring(prompt))
cmd = io.read() or 'quit'
if cmd == "quit" then Lua, result = true, true break end
Lua, result = pcall(load("return " .. cmd or false, name, "t", env))
if Lua and result then
io.write(("%s"):format(tostring(result)))
else
goto exception
end
end
--------------------------------------------------------------------------------------------------------------
-- Errorhandler
::exception::
io.write(("%s\n"):format("Exception"))
if not Lua or not result then
io.output(io.stderr)
io.write(("[%s][%s][%s]\n\27[1;31m>>-Exception->\27[0m %s\n"):format(os.date(), _VERSION, cmd, result)):flush()
io.output(io.stdout)
collectgarbage()
goto lua
end
goto lua
end
--------------------------------------------------------------------------------------------------------------
-- EXAMPLE ---------------------------------------------------------------------------------------------------
-- Lua = require("interpreter")
Lua() -- UNCOMMENT-> For direct execution like: /bin/lua interpreter.lua
return Lua -- UNCOMMENT-> For: Lua = require("interpreter")
Ctrl&C quits hardly
Ctrl&D is only an exception
...and os.exit(0) do an clean exit with returncode 0.
Impression
I try to implement a CLI with 2 commands:
run that spawns an unix socket at /my/path/file.sock and produces output
watch that connects to the socket and forward the output to its own output
When I kill the watch command, I can't understand why the run command is also killed. They don't raise any exception nor sys signal. I noticed that the problems comes from the flush function. Once called, it acts like a exit 0. How come?
Here the sources: https://github.com/soywod/comodoro
The server has to listen for client disconnection and remove the connection from the conn list.
Something like this might work:
let client_thread conn =
let in_ch = in_channel_of_descr conn in
while true do
try input_line in_ch |> ignore
with End_of_file ->
(* Remove conn from !conn and close the conn *)
done
in
let add_conn () =
(* ... *)
Thread.create client_thread conn |> ignore;
(* ... *)
in
I'm trying to write an ocamlbuild plugin. The goal is to build Qt apps (without OCaml code for the time being). To handle the final linking phase, I have written the list of objs, mocs, uis and rcs in a .qtobjs file (like a .itarget), and the list of Qt libs in a .qtpackages file. The rule that applies to these files parses these lists and dynamically builds the objects, mocs and so on before linking everything.
The problem is that I would like not to dynamically build the targets that have not changed. See the rule below:
rule "Link a c++ executable that uses Qt."
~deps:["%.qtobjs"; "%.qtpackages"]
~prod:"%.cxxnative"
(fun env build ->
let dir = Pathname.dirname (env "%.qtobjs") in
let output = env "%.cxxnative" in
let objlist = pwd / (env "%.qtobjs") in
let liblist = pwd / (env "%.qtpackages") in
let packages = read_lines liblist in
let lflags = List.map (fun p -> "-l"^p) packages
# find_all "lflags" in
let objs = List.map (fun o -> dir / o) (read_lines objlist) in
(* Here, I would like to forget the targets that have not changed *)
let objs_to_build = List.filter
(fun target ->
(* something to tell if "target" has to be rebuilt *))
objs in
(* This is where I build the dependencies : *)
let success_builds = build
(List.map (fun o -> [o])
objs_to_build) in
let objects = filter_map
(function
| Outcome.Good x when get_extension x = "opp" ->
Some (pwd / "_build" / (update_extension "o" x))
| Outcome.Good _ -> None
(* Because I don't want to link the ui.h file generated by uic *)
| Outcome.Bad exn -> raise exn)
success_builds in
let tags_objs = tags_of_pathname (env "%.qtobjs") ++ "link" in
let tags_packs = tags_of_pathname (env "%.qtpackages") in
Cmd (S [A (find_one "cxx"); T tags_objs; T tags_packs; Command.atomize lflags;
A "-o"; P output; Command.atomize objects]));
I would like not to call "build" when it's not necessary.
NB: a function
newer_than: Pathname.t -> Pathname.t -> bool
could solve my problem.
Problem solved.
For those who are interested, the problem was in the COMPILING rule : because the ".o" rule was already used by ocamlbuild, I registered it to officially produce ".opp" files but the command actually wrote .o files. So when recompiling, ocamlbuild had no clue that the object file was already present.
Three options:
replace the default ".o" rule (I don't even know if it is possible ?),
produce ".opp" files (but it's less standard),
or alter the compiling rule to do Nop if the .o file exists:
if Pathname.exists (env "%.o") then Nop
else Cmd (S [A ("c++");
A "-c";
A "-o"; P (env "%.o"); P (env "%.cpp")]));
macro module:
-module(macro).
-include_lib("eunit/include/eunit.hrl").
-define(EXPAND(_T), ??_T).
macro_test() ->
?assertEqual("Test", ?EXPAND(Test)),
?assertEqual("Test.test", ?EXPAND(Test.test)).
Is resulting :
6> c(macro).
{ok,macro}
7> eunit:test(macro).
macro: macro_test (module 'macro')...*failed*
in function macro:'-macro_test/0-fun-1-'/1 (macro.erl, line 9)
**error:{assertEqual_failed,[{module,macro},
{line,9},
{expression,"? EXPAND ( Test . test )"},
{expected,"Test.test"},
{value,"Test . test"}]}
=======================================================
Failed: 1. Skipped: 0. Passed: 0.
error
Am I doing something wrong or is this a known bug?
TIA
You're incorrectly assuming that the Erlang compiler treats Test.test as a single token. If you pass the -P option to erlc and examine the output, you'll see that the preprocessor breaks it into multiple tokens. Here's the interesting part of macro.P produced by erlc -P macro.erl:
macro_test() ->
begin
fun(__X) ->
case "Test" of
__X ->
ok;
__V ->
error({assertEqual,
[{module,macro},
{line,8},
{expression,"? EXPAND ( Test )"},
{expected,__X},
{value,__V}]})
end
end("Test")
end,
begin
fun(__X) ->
case "Test . test" of
__X ->
ok;
__V ->
error({assertEqual,
[{module,macro},
{line,9},
{expression,"? EXPAND ( Test . test )"},
{expected,__X},
{value,__V}]})
end
end("Test.test")
end.
I need continuously show stdout/stderr from os command in erlang.
In ruby I can implement it with following code:
s1, s2 , s3, t = Open3.popen3('for %a in (1 2 3 4 5 6 7 8 9) do (echo message & sleep 2 ) 2>&1 ')
s2.each do |l|
puts l
end
it will show 'message\n message\n' in 'real time' - does not wait end of process.
I've tried os:cmd(..)
and
1> P5 = erlang:open_port({spawn, "ruby rtest.rb"}, [stderr_to_stdout, in, exit_s
tatus, binary,stream, {line, 255}]).
#Port<0.505>
2> receive {P5, Data} -> io:format("Data ~p~n",[Data]) end.
Data {data,{eol,<<>>}}
ok
but both of them wait end of process.
Are the any optional for continuously stdout reading in Erlang?
EDIT:
In other words I look for a popen (c/c++; proc_open(php) and etc) function in erlang
EDIT2
Code, that works on linux (tested on centos6.2). Thanks for vinod:
-module(test).
-export([run/0]).
run() ->
P5 = erlang:open_port({spawn, "sh test.sh"},
[stderr_to_stdout, in, exit_status,stream, {line, 255}]),
loop(P5).
loop(P) ->
receive{P, Data} ->
io:format("Data ~p~n",[Data]),
loop(P)
end.
Output:
10> c(test).
{ok,test}
11> test:run().
Data {data,{eol,"1"}}
Data {data,{eol,"2"}}
Data {data,{eol,"3"}}
Data {data,{eol,"4"}}
Data {data,{eol,"5"}}
Data {data,{eol,"6"}}
Data {data,{eol,"7"}}
Data {data,{eol,"8"}}
Data {data,{eol,"9"}}
Data {data,{eol,"10"}}
Data {exit_status,0}
If I understand correctly, you want to continue to execute your program in concurrent with the os command. In Erlang you can just spawn a process which does that and you can continue. For example
1> spawn(fun() ->
P5 = erlang:open_port({spawn, "ruby rtest.rb"},
[stderr_to_stdout, in, exit_status,
binary,stream, {line, 255}]),
receive {P5, Data} ->
io:format("Data ~p~n",[Data])
end
end).
<0.32.0>
2> 5+5.
10
3>
Better to write in a module so that you can understand it better.