查看源代码 escript
运行用 Erlang 编写的脚本。
概要
script-name [arg1 arg2...]
描述
escript
提供对运行简短 Erlang 程序的支持,而无需先编译它们,并提供一种简单的方式来检索命令行参数。 escript
通过手动编写或使用 escript:create/2
来创建。
escript 通过直接调用它们来运行(在 Windows 上不起作用)
script-name [arg1 arg2...]
或通过调用 escript
程序(在所有平台上都适用)
escript [escript-flags] script-name.escript [arg1 arg2...]
例如
$ chmod u+x factorial
$ cat factorial
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -sname factorial -mnesia debug verbose
main([String]) ->
try
N = list_to_integer(String),
F = fac(N),
io:format("factorial ~w = ~w\n", [N,F])
catch
_:_ ->
usage()
end;
main(_) ->
usage().
usage() ->
io:format("usage: factorial integer\n"),
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
示例中 Erlang 脚本的头部与普通的 Erlang 模块不同。第一行旨在成为解释器行,它调用 escript
。
但是,如果像下面这样调用 escript
,则第一行的内容无关紧要,但它不能包含 Erlang 代码,因为它将被忽略
$ escript factorial 5
示例中的第二行包含一个针对 Emacs
编辑器的可选指令,这会使其进入编辑 Erlang 源文件的主模式。如果存在该指令,则它必须位于第二行。
如果存在选择 编码 的注释,则它可以位于第二行。
注意
上述注释指定的编码适用于脚本本身。但是,必须按如下方式显式设置 I/O 服务器的编码
io:setopts([{encoding, latin1}])
如果支持,
standard_io
的 I/O 服务器的默认编码为unicode
。(请参阅 STDLIB 用户指南中的 选项摘要 部分。)
在第三行(或第二行,取决于 Emacs 指令是否存在),可以为模拟器指定参数,例如
%%! -sname factorial -mnesia debug verbose
这样的参数行必须以 %%!
开头,并且剩余行将被解释为模拟器的参数。
如果您知道 escript
可执行文件的位置,则第一行可以直接给出 escript
的路径,例如
#!/usr/local/bin/escript
与任何其他类型的脚本一样,如果未设置脚本文件的执行位,则 Erlang 脚本在 Unix 平台上不起作用。(要打开执行位,请使用 chmod +x script-name
。)
剩余的 Erlang 脚本文件可以包含 Erlang *源代码*、*内联 beam 文件*或*内联存档文件*。
Erlang 脚本文件必须始终包含 main/1
函数。当脚本运行时,将使用表示为脚本指定的参数的字符串列表(不以任何方式更改或解释)调用 main/1
函数。
如果脚本中的 main/1
函数成功返回,则脚本的退出状态为 0
。如果在执行过程中生成异常,则会打印一条简短消息,并且脚本将以退出状态 127
终止。
要返回您自己的非零退出代码,请调用 halt(ExitCode)
,例如
halt(1).
要检索脚本的路径名,请从您的脚本中调用 escript:script_name/0
(路径名通常但并非总是绝对的)。
如果文件包含源代码(如上面的示例中),则它将由 epp
预处理器处理。这意味着,例如,您可以使用预定义的宏(例如 ?MODULE
)并包含诸如 -include_lib
指令之类的指令。例如,使用
-include_lib("kernel/include/file.hrl").
包含函数 file:read_link_info/1
使用的记录的记录定义。您还可以通过在此处包含编码注释来选择编码,但是如果第二行存在有效的编码注释,则它优先。
在运行之前,将检查脚本的语法和语义正确性。如果存在警告(例如未使用的变量),则会打印它们,并且脚本仍将运行。如果存在错误,则会打印它们,并且脚本将不会运行,其退出状态为 127
。
main/1
函数的模块声明和导出声明都是可选的。
默认情况下,脚本将由 Erlang 编译器编译。
可以通过在脚本文件中包含以下行来强制解释它
-mode(interpret).
解释代码的执行速度比编译代码慢,并且某些语言结构将不起作用,但不需要 Erlang 编译器应用程序可用。
更改
在 Erlang/OTP 27 之前,脚本默认会被解释。
预编译的 escript
脚本还可以包含预编译的 beam
代码。要创建预编译的 escript,建议您使用 escript:create/2
。在预编译的脚本中,脚本头部的解释与包含源代码的脚本中的解释相同。这意味着您可以通过在文件开头添加以 #!
和 %%!
开头的行来使 beam
文件可执行。在预编译的脚本中,必须导出 main/1
函数。
另一个选择是在脚本中包含整个 Erlang 存档。在存档脚本中,脚本头部的解释与包含源代码的脚本中的解释相同。这意味着您可以通过在文件开头添加以 #!
和 %%!
开头的行来使存档文件可执行。在存档脚本中,必须导出 main/1
函数。默认情况下,将调用与 escript
文件基本名称相同的模块中的 main/1
函数。可以通过将标志 -escript main Module
设置为模拟器标志之一来覆盖此行为。Module
必须是具有导出的 main/1
函数的模块的名称。有关存档和代码加载的更多信息,请参阅 escript
和 code
。
在 escript 中包含头部通常非常方便,尤其是在 Unix 平台上。但是,头部是可选的,因此您可以直接“执行”Erlang 模块、Beam 文件或存档文件,而无需向其中添加任何头部。但是,您必须按如下方式调用脚本
$ escript factorial.erl 5
factorial 5 = 120
$ escript factorial.beam 5
factorial 5 = 120
$ escript factorial.zip 5
factorial 5 = 120
捆绑 escript
可以将 escript
与 Erlang 运行时系统捆绑在一起,使其自给自足且可重定位。在这样一个独立的系统中,escript
应位于独立系统的顶部 bin
目录中,并以 .escript
作为文件扩展名。此外,应将(内置的)escript
程序复制到同一目录中,并赋予脚本的原始名称(不带 .escript
扩展名)。这将启用对捆绑的 Erlang 运行时系统的使用。
(内置的)escript
程序首先确定要使用的 Erlang 运行时系统,然后启动它以执行您的脚本。通常,运行时系统位于与 escript
程序本身相同的 Erlang 安装中。但是,对于具有一个或多个 escript 的独立系统,可能您路径中的 escript
程序实际上会启动与 escript 捆绑的运行时系统。这是有意的,并且通常在独立系统的 bin
目录不在执行路径中时发生(因为它可能会导致其 erl
程序覆盖所需的程序),并且通过路径中 bin
目录中的符号链接来引用 escript
。
escript 接受的选项
-c
- 编译 escript,而不管模式属性的值如何。-d
- 调试 escript。启动调试器,将包含main/1
函数的模块加载到调试器中,在main/1
中设置断点,然后调用main/1
。如果模块是预编译的,则必须使用选项debug_info
显式编译它。-i
- 解释 escript,而不管模式属性的值如何。-s
- 对脚本文件执行语法和语义检查。警告和错误(如果有)将写入标准输出,但不会运行脚本。如果发现任何错误,则退出状态为0
,否则为127
。
注意
还可以使用
erl
理解的环境变量来控制escript
调用的 Erlang 模拟器的配置。