檢視原始碼 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 腳本名稱。)

剩餘的 Erlang 腳本檔案可以包含 Erlang *原始碼*、*內嵌的 beam 檔案*或*內嵌的封存檔案*。

Erlang 腳本檔案必須始終包含 main/1 函式。執行腳本時,會使用一個字串列表來呼叫 main/1 函式,該列表代表指定給腳本的引數(不會以任何方式變更或解釋)。

如果腳本中的 main/1 函式成功返回,則腳本的結束狀態為 0。如果在執行期間產生例外,則會列印一條簡短訊息,並且腳本會以結束狀態 127 終止。

要返回您自己的非零結束碼,請呼叫 halt(結束碼),例如

halt(1).

要檢索腳本的路徑名稱,請從您的腳本中呼叫 escript:script_name/0(路徑名稱通常(但不總是)是絕對路徑)。

如果檔案包含原始碼(如上述範例所示),則會由 epp 前置處理器處理。這表示您可以使用預先定義的巨集(例如 ?MODULE)和 include 指令,例如 -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 模組 設定為模擬器旗標之一來覆寫此行為。模組必須是具有匯出的 main/1 函式的模組名稱。有關封存和程式碼載入的詳細資訊,請參閱 escriptcode

在 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(s) 與 Erlang 執行時間系統捆綁在一起,使其自給自足且可重定位。在這樣的獨立系統中,escript(s) 應位於獨立系統的頂層 bin 目錄中,並給定 .escript 作為檔案副檔名。此外,應將(內建的)escript 程式複製到相同目錄,並給定腳本的原始名稱(不帶 .escript 副檔名)。這將啟用捆綁的 Erlang 執行時間系統的使用。

(內建的)escript 程式會先判斷要使用的 Erlang 執行時間系統,然後啟動它來執行您的腳本。通常,執行時間系統與 escript 程式本身位於相同的 Erlang 安裝中。但是,對於具有一個或多個 escript 的獨立系統,您路徑中的 escript 程式實際上可能會啟動與 escript 捆綁的執行時間系統。這是故意的,並且通常發生在獨立系統的 bin 目錄不在執行路徑中時(因為它可能會導致其 erl 程式覆寫所需的程式),並且 escript(s) 是透過路徑中的 bin 目錄中的符號連結來引用的。

escript 接受的選項

  • -c - 無論模式屬性的值為何,都會編譯 escript。

  • -d - 除錯 escript。啟動除錯器,將包含 main/1 函式的模組載入到除錯器中,在 main/1 中設定中斷點,並呼叫 main/1。如果模組是預先編譯的,則必須使用選項 debug_info 顯式編譯。

  • -i - 無論模式屬性的值為何,都會解釋 escript。

  • -s - 執行腳本檔案的語法和語義檢查。警告和錯誤(如果有的話)會寫入標準輸出,但是不會執行腳本。如果發現任何錯誤,結束狀態為 0,否則為 127

注意

也可以使用 erl 理解的環境變數來控制 escript 呼叫的 Erlang 模擬器的組態。