我是靠谱客的博主 强健烧鹅,最近开发中收集的这篇文章主要介绍erlang escript使用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Erlang scripting support 让erlang可以向unix script 一样做脚本使用。

script-name script-arg1 script-arg2...escript escript-flags script-name script-arg1 script-arg2...


以下是一个例子

$ chmod u+x factorial
$ cat factorial
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose
main([String]) ->
try
N = list_to_integer(String),
F = fac(N),
io:format("factorial ~w = ~wn", [N,F])
catch
_:_ ->
usage()
end;
main(_) ->
usage().
usage() ->
io:format("usage: factorial integern"),
halt(1).
fac(0) -> 1;
fac(N) -> N * fac(N-1).
$ ./factorial 5
factorial 5 = 120
$ ./factorial
usage: factorial integer
$ ./factorial five
usage: factorial integer

escript模块头不同于普通模块。


第一行用于指定解释器,用于解释escript,但是如果你这样调用脚本

$ escript factorial 5

第一行就不起作用了,但是第一行不能包含代码,将不会被执行。


在上面这个例子中,第二行包含一个可选指令使Emacs 编辑器进入编辑erlang源码模式。该指令只能在第二行。

If there is a comment selecting the encoding it can be located on the second line.

Note

The encoding specified by the above mentioned comment applies to the script itself. The encoding of the I/O-server, however, has to be set explicitly like this:

io:setopts([{encoding, unicode}])

The default encoding of the I/O-server for standard_io is latin1 since the script runs in a non-interactive terminal (see Using Unicode in Erlang).


在第三行可能给模拟器一些参数,例如

%%! -smp enable -sname factorial -mnesia debug verbose

参数行必须以 %%!开始,后面的将被解释为模拟器的参数。

如果你知道可执行文件的路径,第一行你直接写路径,如:

#!/usr/local/bin/escript
像其他脚本一样。如果脚本没有被设置未可执行文件,将不能在unix系统上执行。

脚本文件剩下的内容可以是erlang源码,erlang 内联的beam文件或者erlang的存档文件。



一个erlang脚本文件必须包含main/1函数,当执行脚本时,main函数将被调用,并且伴随一个字符串列表作为参数。

如果main函数执行成功,则返回退出状态0,如果执行过程中出现异常,则一个信息被打印出来,并且脚本结束返回一个退出状态127。

如果想返回执行想要的退出状态值,可以调用halt(ExitCode);例如:

halt(1).

执行 escript:script_name()返回脚本的文件名。

如果脚本包含的是源代码,它将有会被预处理器epp执行。这意味着你可以使用宏定义和include指令,像-include_lib指令,如使用

-include_lib("kernel/include/file.hrl").
来引入函数file:read_link_info/1中使用的记录。

You can also select encoding by including a encoding comment here, but if there is a valid encoding comment on the second line it takes precedence.


脚本在将要运行会被检查语法语义。如果有警告,警告将被打印出来,脚本继续运行,如果有错误,错误被打印出来,脚本停止运行,返回退出状态127。


无论模块声明还main函数导出都是可选的。


默认脚本是解释执行。你可以强制编译通过包含下面的语句在脚本中:

-mode(compile).

解释代码比编译代码执行的慢。如果解释代码比较多,那么编译它是值得的即使编译需要一小会 It is also possible to supply native instead of compile, this will compile the script using the native flag, again depending on the characteristics of the escript this could or could not be worth while.

正如前面提到的,脚本可以包含预编译的beam代码。在一个预编译脚本中,脚本的开头解释和源码的是一样的。这意味着你可以在一个编译好的beam文件前几行加上上面的说的头,在编译的beam中必须导出main/1函数。

As yet another option it is possible to have an entire Erlang archive in the script. In a archive script, the interpretation of the script header is exactly the same as in a script containing source code. That means that you can make an archive file executable by prepending the file with the lines starting with #! and %%! mentioned above. In an archive script, the function main/1 must be exported. By default the main/1 function in the module with the same name as the basename of the escript file will be invoked. This behavior can be overridden by setting the flag -escript main Module as one of the emulator flags. The Module must be the name of a module which has an exported main/1 function. See code(3) for more information about archives and code loading.

在很多情况下脚本里有头很方便,特别是在unix系统里。但是头部是可选的。这意味着你可以执行一个erlang模块,beam文件,archive file 不加头部。但是你必须这么执行文件:

$ escript factorial.erl 5
factorial 5 = 120
$ escript factorial.beam 5
factorial 5 = 120
$ escript factorial.zip 5
factorial 5 = 120


脚本创建

escript:create(FileOrBin, Sections) -> ok | {ok, binary()} | {error, term()}

Types:

FileOrBin = filename() | 'binary'
Sections = [Header] Body | Body
Header = shebang | {shebang, Shebang} | comment | {comment, Comment} | {emu_args, EmuArgs}
Shebang = string() | 'default' | 'undefined'
Comment = string() | 'default' | 'undefined'
EmuArgs = string() | 'undefined'
Body = {source, SourceCode} | {beam, BeamCode} | {archive, ZipArchive} | {archive, ZipFiles, ZipOptions}
SourceCode = BeamCode = file:filename() | binary()
ZipArchive = zip:filename() | binary()
ZipFiles = [ZipFile]
ZipFile = file:filename() | {file:filename(), binary()} | {file:filename(), binary(), file:file_info()}
ZipOptions = [zip:create_option()]

这个函数创建一个脚本通过几个部分。这几个部分是有序的。一个脚本开始以可选的头,紧跟着实体。如果有头,则总是以 shebang开始,可能跟随 a comment and emu_args。shebang 默认是"/usr/bin/env escript"。The comment 默认是 "This is an -*- erlang -*- file"。这个函数可以返回binary或者被写如文件。

作为一个例子我们展示这个函数如何使用,我们创建一个解释脚本使用emu_args来set一些模拟器标志。在这个例子中不支持smp。我们从新创建的脚本中提取不同的部分:

> Source = "%% Demonmain(_Args) ->n
io:format(erlang:system_info(smp_support)).n".
"%% Demonmain(_Args) ->n
io:format(erlang:system_info(smp_support)).n"
> io:format("~sn", [Source]).
%% Demo
main(_Args) ->
io:format(erlang:system_info(smp_support)).
ok
> {ok, Bin} = escript:create(binary, [shebang, comment, {emu_args, "-smp disable"},
{source, list_to_binary(Source)}]).
{ok,<<"#!/usr/bin/env escriptn%% This is an -*- erlang -*- filen%%!-smp disabl"...>>}
> file:write_file("demo.escript", Bin).
ok
> os:cmd("escript demo.escript").
"false"
> escript:extract("demo.escript", []).
{ok,[{shebang,default}, {comment,default}, {emu_args,"-smp disable"},
{source,<<"%% Demonmain(_Args) ->n
io:format(erlang:system_info(smp_su"...>>}]}

一个没有头部的脚本可以被这么创建:

> file:write_file("demo.erl",
["%% demo.erln-module(demo).n-export([main/1]).nn", Source]).
ok
> {ok, _, BeamCode} = compile:file("demo.erl", [binary, debug_info]).
{ok,demo,
<<70,79,82,49,0,0,2,208,66,69,65,77,65,116,111,109,0,0,0,
79,0,0,0,9,4,100,...>>}
> escript:create("demo.beam", [{beam, BeamCode}]).
ok
> escript:extract("demo.beam", []).
{ok,[{shebang,undefined}, {comment,undefined}, {emu_args,undefined},
{beam,<<70,79,82,49,0,0,3,68,66,69,65,77,65,116,
111,109,0,0,0,83,0,0,0,9,...>>}]}
> os:cmd("escript demo.beam").
"true"

下面我们创建archive script 同时包含源码和beam,然后我们遍历里面的所有文件,收集他们的内容和信息。

> {ok, SourceCode} = file:read_file("demo.erl").
{ok,<<"%% demo.erln-module(demo).n-export([main/1]).nn%% Demonmain(_Arg"...>>}
> escript:create("demo.escript",
[shebang,
{archive, [{"demo.erl", SourceCode},
{"demo.beam", BeamCode}], []}]).
ok
> {ok, [{shebang,default}, {comment,undefined}, {emu_args,undefined},
{archive, ArchiveBin}]} = escript:extract("demo.escript", []).
{ok,[{shebang,default}, {comment,undefined}, {emu_args,undefined},
{{archive,<<80,75,3,4,20,0,0,0,8,0,118,7,98,60,105,
152,61,93,107,0,0,0,118,0,...>>}]}
> file:write_file("demo.zip", ArchiveBin).
ok
> zip:foldl(fun(N, I, B, A) -> [{N, I(), B()} | A] end, [], "demo.zip").
{ok,[{"demo.beam",
{file_info,748,regular,read_write,
{{2010,3,2},{0,59,22}},
{{2010,3,2},{0,59,22}},
{{2010,3,2},{0,59,22}},
54,1,0,0,0,0,0},
<<70,79,82,49,0,0,2,228,66,69,65,77,65,116,111,109,0,0,0,
83,0,0,...>>},
{"demo.erl",
{file_info,118,regular,read_write,
{{2010,3,2},{0,59,22}},
{{2010,3,2},{0,59,22}},
{{2010,3,2},{0,59,22}},
54,1,0,0,0,0,0},
<<"%% demo.erln-module(demo).n-export([main/1]).nn%% Demonmain(_Arg"...>>}]}

提取脚本头部

escript:extract(File, Options) -> {ok, Sections} | {error, term()}

这个函数分析脚本并且提取脚本头部。跟函数create/2.是反向的。

所有的头部都返回即使在脚本中不存在。如果某部分跟默认值一样,则所提取的值设置为默认的。如果某个部分没有则被设置为原子undefined。

compile_source选项只是对脚本中是源码的结果起效果。在这中情况下,源码自动编译返回{source, BeamCode}而不是{source, SourceCode}


escript:script_name() -> File

Types:

File = filename()

这个函数返回正在执行脚本的名字。如果函数在脚本之外执行,这个行为未被定义。


脚本接受的参数。

-d 选项 用来调试script的 
-c  编译执行 
-i  解释执行 
-s  只检查不执行 

-n 编译脚本用  +native flag

最后

以上就是强健烧鹅为你收集整理的erlang escript使用的全部内容,希望文章能够帮你解决erlang escript使用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部