从Erlang调用shell脚本时,我通常需要退出状态(0或其他),所以我使用这个函数运行它们:
%% in module util
os_cmd_exitstatus(Action, Cmd) ->
?debug("~ts starting... Shell command: ~ts", [Action, Cmd]),
try erlang:open_port({spawn, Cmd}, [exit_status, stderr_to_stdout]) of
Port ->
os_cmd_exitstatus_loop(Action, Port)
catch
_:Reason ->
case Reason of
badarg ->
Message = "Bad input arguments";
system_limit ->
Message = "All available ports in the Erlang emulator are in use";
_ ->
Message = file:format_error(Reason)
end,
?error("~ts: shell command error: ~ts", [Action, Message]),
error
end.
os_cmd_exitstatus_loop(Action, Port) ->
receive
{Port, {data, Data}} ->
?debug("~ts... Shell output: ~ts", [Action, Data]),
os_cmd_exitstatus_loop(Action, Port);
{Port, {exit_status, 0}} ->
?info("~ts finished successfully", [Action]),
ok;
{Port, {exit_status, Status}} ->
?error("~ts failed with exit status ~p", [Action, Status]),
error;
{'EXIT', Port, Reason} ->
?error("~ts failed with port exit: reason ~ts",
[Action, file:format_error(Reason)]),
error
end.
这很好用,直到我用这个来启动一个程序并退出程序的脚本:
#!/bin/sh
FILENAME=$1
eog $FILENAME &
exit 0
(在实际的用例中,还有更多的参数,并且在传递给程序之前进行了一些按摩)。从终端运行时,它会显示图像并立即退出,如预期的那样。
但从Erlang运行却没有。在日志文件中,我看到它开始正常:
22/Mar/2011 13:38:30.518 Debug: Starting player starting... Shell command: /home/aromanov/workspace/gmcontroller/scripts.dummy/image/show-image.sh /home/aromanov/workspace/media/images/9e89471e-eb0b-43f8-8c12-97bbe598e7f7.png
,出现eog
窗口。但我不得到
22/Mar/2011 13:47:14.709 Info: Starting player finished successfully
直到杀死eog
进程(使用kill
或仅关闭窗口),这不符合我的要求。为什么行为不同?有办法解决吗?
答案 0 :(得分:2)
通常,如果在shell脚本中使用&
在后台运行命令,并且shell脚本在命令之前终止,则命令将变为孤立状态。可能是erlang试图阻止open_port中的孤立进程并等待eog
终止。通常,如果要在shell脚本期间在后台运行某些内容,则应在脚本末尾放入wait
以等待后台进程终止。但这正是你不想做的事情。
您可以在shell脚本中尝试以下操作:
#!/bin/sh
FILENAME=$1
daemon eog $FILENAME
# exit 0 not needed: daemon returns 0 if everything is ok
如果您的操作系统有daemon
命令。我在FreeBSD上签了一个,它有一个:daemon(8)
这不是所有类Unix系统都可用的命令,但是在您的操作系统中可能有不同的命令执行相同的操作。
守护程序实用程序将自己与控制终端分离,并执行其参数指定的程序。
我不确定这是否能解决你的问题,但我怀疑eog
某种程度上依赖于stdin / stdou作为一种控制终端。值得一试。
这也应该可以解决工作控制错误地 的问题,这也可能导致问题。由于daemon
确实正常退出,因此shell退出时无法尝试等待后台作业,因为在shell视图中没有。
说完这一切:为什么不在eog
运行时让Erlang保持打开状态?
以:
开头#!/bin/sh
FILENAME=$1
exec eog $FILENAME
使用exec
调用它不会将它替换为使用eog
替换shell进程。您将在Erlang中看到的退出状态将在eog
终止时成为状态。如果你想这样做,你也可以关闭端口并从Erlang终止eog
。
答案 1 :(得分:1)
也许你的/bin/sh
在不以交互方式运行时不支持作业控制?至少我的Ubuntu系统上的/bin/sh
(实际dash(1)
!)提到:
-m monitor Turn on job control (set automatically
when interactive).
当您从终端运行脚本时,shell可能会识别出它正在以交互方式运行并支持作业控制。当您将shell脚本作为端口运行时,shell可能在没有作业控制的情况下运行。