如何在Erlang中执行系统命令并使用os:cmd/1获取结果?

9
当我尝试在Windows上执行以下命令,如果返回错误或不存在,我总是得到一个空列表而不是返回的字符串错误,例如:
我会得到:
[] = os:cmd("blah").

代替类似于

这样的东西
"command not found" = os:cmd("blah").

在Linux中,当我执行一个命令时,如果一切正常,它会按预期工作,否则会出现"/bin/sh: line 1: blah: command not found\n"的错误提示。因此,当我需要知道执行结果等信息时,我不能依赖该功能。请给出一些通用的方法,以便能够执行命令并获取结果,包括错误代码。谢谢!

这种行为只能通过使用werl.exe观察,而不能使用erl.exe。 - user3169252
请问您能否在 erl.exe 和 werl.exe 中展示 os:get_env("COMSPEC")erlang:system_info(os_type) 的结果? - Viacheslav Kovalev
在两种情况下(erl/werl),我得到相同的以下结果:1> os:getenv("COMSPEC"). "C:\Windows\system32\cmd.exe" 2> erlang:system_info(os_type). {win32,nt} - user3169252
1个回答

12

我对Windows完全不熟悉,但我确定你应该看看这里。这是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将返回进程退出代码以及进程标准输出。


可能是由于时间过去太久或者Erlang世界发生了足够的变化,导致协议已经改变,但每当我使用它时,我从未在接收匹配中遇到{'EXIT',Port,_}分支。无论命令是否退出0、非零或因信号而死亡,我从未观察到匹配该模式的消息。这是必要的吗? - mkomitee
在这种情况下,您不需要处理EXIT,因为您正在使用eof选项。 - mkomitee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接