Как выполнить системную команду в Erlang и получить результат с помощью os:cmd/1?

Когда я пытаюсь выполнить следующую команду, которая возвращает ошибку или не завершается в Windows, я всегда получаю пустой список вместо ошибки, возвращаемой в виде строки, например:

Я получил:

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

вместо чего-то вроде

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

В linux все работает как положено, поэтому я получаю "/bin/sh: строка 1: blah: команда не найдена\n"

Поэтому я не могу полагаться на эту функцию, когда мне нужно знать, как завершилось выполнение и т. д. Пожалуйста, предложите какой-нибудь общий способ выполнения команды и получения результатов, включая код ошибки.

Спасибо!


person user3169252    schedule 19.11.2014    source источник
comment
такое поведение можно наблюдать только при использовании werl.exe, а не erl.exe   -  person user3169252    schedule 20.11.2014
comment
Не могли бы вы показать результаты os:get_env("COMSPEC") и erlang:system_info(os_type) в erl.exe и werl.exe, пожалуйста?   -  person Viacheslav Kovalev    schedule 20.11.2014
comment
В обоих случаях (erl/werl) я получаю одинаковые результаты: 1 > os:getenv(COMSPEC). C:\\Windows\\system32\\cmd.exe 2> erlang:system_info(os_type). {win32,нт}   -  person user3169252    schedule 20.11.2014


Ответы (1)


Я совсем не знаком с окнами, но уверен, вам стоит посмотреть это. Это функция реализации os:cmd/1.

Проблема с os:cmd/1. Эта функция не дает вам знать, было ли выполнение команды успешным или нет, поэтому вам нужно полагаться только на определенное поведение командной оболочки (которое зависит от платформы).

Я бы рекомендовал вам использовать функцию erlang:open_port/2. Что-то такое:

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.

Таким образом, функция my_exec/1 вернет процесс код выхода вместе со стандартным выводом процесса.

person Viacheslav Kovalev    schedule 20.11.2014
comment
Может быть, прошло слишком много времени или в мире erlang изменилось достаточно, чтобы изменился протокол, но всякий раз, когда я использую это, у меня никогда не было ветки {'EXIT', Port, _} в совпадении приема. Независимо от того, возвращает ли команда 0, ненулевое значение или умирает из-за сигнала, я никогда не видел сообщения, соответствующего этому шаблону. Это необходимо? - person mkomitee; 04.10.2016
comment
В этом случае вам не нужно обрабатывать EXIT, потому что вы используете параметр eof. - person mkomitee; 04.10.2016