How to execute system command in Erlang and get results using os:cmd/1?
Asked Answered
T

1

9

When I try to execute following command that returns error or doesn't exit on Windows - I always get empty list instead of error returned as string so for example:

I get:

[] = os:cmd("blah").

instead of something like

"command not found" = os:cmd("blah").

In linux - everything works as expected so I get "/bin/sh: line 1: blah: command not found\n"

Therefore I cannot rely on that function when I need to know how execution finished etc. Please suggest some general way how to execute command and get results including error code.

Thanks!

Twink answered 19/11, 2014 at 22:45 Comment(3)
this behavior can be observed only using werl.exe - not erl.exeTwink
Could you show results of os:get_env("COMSPEC") and erlang:system_info(os_type) in erl.exe and werl.exe, please?Bevus
In both cases (erl/werl) I get same following results: 1> os:getenv("COMSPEC"). "C:\\Windows\\system32\\cmd.exe" 2> erlang:system_info(os_type). {win32,nt}Twink
B
12

I am not familiar with windows at all, but I'm sure, you should look this. This is implementation os:cmd/1 function.

There is problem with os:cmd/1. This function doesn't let you know, was command execution successful or not, so you only have to rely on certain command shell behaviour (which is platform dependent).

I'd recommend you to use erlang:open_port/2 function. Something like that:

my_exec(Command) ->
    Port = open_port({spawn, Command}, [stream, in, eof, hide, exit_status]),
    get_data(Port, []).

get_data(Port, Sofar) ->
    receive
    {Port, {data, Bytes}} ->
        get_data(Port, [Sofar|Bytes]);
    {Port, eof} ->
        Port ! {self(), close},
        receive
        {Port, closed} ->
            true
        end,
        receive
        {'EXIT',  Port,  _} ->
            ok
        after 1 ->              % force context switch
            ok
        end,
        ExitCode =
            receive
            {Port, {exit_status, Code}} ->
                Code
        end,
        {ExitCode, lists:flatten(Sofar)}
    end.

So function my_exec/1 will return process exit code along with process stdout.

Bevus answered 20/11, 2014 at 19:6 Comment(2)
It may be that too much time has gone by or that enough has changed in the erlang world that the protocol has changed, but whenever I use this, I've never had the {'EXIT', Port, _} branch in the receive match. Whether the command exits 0, nonzero, or dies due to a signal, I've never observed a message matching that pattern. Is it necessary?Doordie
You don't need to handle the EXIT in this case because you're using the eof option.Doordie

© 2022 - 2024 — McMap. All rights reserved.