查看源碼 系統 (Elixir v1.16.2)
系統 模組提供直接與 VM 或主機系統進行交互的函數。
時間
系統 模組還提供與時間有關的函數,返回系統保留的不同時間,支持不同的時間單位。
依賴系統時間的複雜性之一是它們可能會被調整。例如,當您進入和離開夏令時時,系統時鐘將被調整,通常增加或減少一個小時。我們將這種變化稱為「時間扭曲」。為了理解這種變化可能造成的危害,想像一下以下代碼
## DO NOT DO THIS
prev = System.os_time()
# ... execute some code ...
next = System.os_time()
diff = next - prev
如果在代碼執行時,系統時鐘更改,則一些在1秒內執行的代碼可能會被報告為花費了1小時以上!為了解決這些問題,VM 通過 System.monotonic_time/0
提供單調時間,該時間永不減少且不跳躍
## DO THIS
prev = System.monotonic_time()
# ... execute some code ...
next = System.monotonic_time()
diff = next - prev
一般來說,VM 提供三種時間測量
os_time/0
- 操作系統(OS)報告的時間。此時間可以向前或向後調整,沒有限制;system_time/0
- VM 對os_time/0
的觀點。在時間扭曲的情況下,系統時間和操作系統時間可能不匹配,儘管 VM 致力於將它們對齊。此時間不是單調的(即可能會減少),因為其行為是由 VM 時間扭曲模式配置的 請參閱 VM 時間扭曲模式;monotonic_time/0
- Erlang VM 提供的單調增加的時間。這不是嚴格的單調增加。函數的多個連續調用可能返回相同的值。
此模組中的時間函數使用本機單位(除非另有指定),其操作系統取決於本機。大多數情況下,所有計算均在本機單位中進行,以避免精度損失,最後使用convert_time_unit/3
將時間轉換為特定時間單位,如:millisecond
或:microsecond
。詳情請參閱time_unit/0
類型。
有關虛擬機對不同時間的支持的更完整說明,請參閱Erlang文檔中有關時間和時間校正的章節。
摘要
函數
列出命令行參數。
修改命令行參數。
註冊程序退出處理程序函數。
Elixir構建信息。
執行帶有參數args
的給定command
。
返回系統編譯時的字節序。
將時間從時間單位from_unit
轉換為時間單位to_unit
。
當前工作目錄。
當前工作目錄,錯誤時引發異常。
刪除環境變量。
返回字節序。
返回給定環境變量的值,如果未找到則返回:error
。
返回給定環境變量的值,如果未找到則引發異常。
在系統上查找可執行文件。
返回所有系統環境變量。
返回給定環境變量的值。
Erlang虛擬機進程標識符。
立即停止Erlang運行時系統。
返回當前單調時間,單位為:native
。
返回以給定時間單位表示的當前單調時間。
檢查系統是否在處理ARGV結束時會停止。
標記系統是否應在處理ARGV結束時停止。
返回當前操作系統(OS)時間。
返回以給定時間unit
表示的當前操作系統(OS)時間。
返回Erlang/OTP發行版本號。
返回當前Erlang運行時系統實例的操作系統PID。
設置多個環境變量。
設置環境變量值。
重新啟動Erlang運行時系統中的所有應用程序。
返回VM中計劃程序的數量。
返回VM中正在線計劃程序的數量。
在操作系統shell中執行給定的command
。
獲取上次異常堆棧跟踪的已棄用機制。
異步且謹慎地停止Erlang運行時系統。
返回當前系統時間,單位為:native
。
返回以給定時間單位表示的當前系統時間。
返回Erlang VM單調時間與Erlang VM系統時間之間的當前時間偏移。
返回Erlang VM單調時間與Erlang VM系統時間之間的當前時間偏移。
可寫入的臨時目錄。
可寫入的臨時目錄,在錯誤時會引發異常。
捕獲給定的signal
以執行fun
。
生成並返回在當前運行時實例中唯一的整數。
移除之前註冊的帶有 id
的 signal
。
使用者主目錄。
使用者主目錄,在錯誤時引發異常。
Elixir 版本信息。
等待系統啟動。
類型
@type signal() ::
:sigabrt
| :sigalrm
| :sigchld
| :sighup
| :sigquit
| :sigstop
| :sigterm
| :sigtstp
| :sigusr1
| :sigusr2
@type time_unit() :: :second | :millisecond | :microsecond | :nanosecond | pos_integer()
要傳遞給函數如monotonic_time/1
等的時間單位。
:second
、:millisecond
、:microsecond
和 :nanosecond
這些時間單位控制接受時間單位的函數的返回值。
時間單位也可以是嚴格的正整數。在這種情況下,它代表"每秒部分":時間將以 1 / parts_per_second
秒返回。例如,使用 :millisecond
時間單位等同於使用 1000
作為時間單位(因為時間將以1/1000秒 - 毫秒返回)。
函數
@spec argv() :: [String.t()]
列出命令行參數。
返回傳遞給程序的命令行參數列表。
@spec argv([String.t()]) :: :ok
修改命令行參數。
更改命令行參數列表。請小心使用,因為它會摧毀任何先前的 argv 信息。
@spec at_exit((non_neg_integer() -> any())) :: :ok
註冊程序退出處理程序函數。
註冊一個將在 Elixir 腳本結束時調用的函數。腳本通常是通過命令行使用 elixir
和 mix
可執行文件啟動的。
處理程序始終在與註冊它的進程不同的進程中執行。因此,調用進程管理的任何資源(ETS 表、打開的文件等)在調用處理程序函數時將不可用。
該函數必須接收退出狀態碼作為參數。
如果虛擬機通過 System.stop/1
、System.halt/1
或退出信號程序終止,at_exit/1
回調函數不保證會執行。
@spec build_info() :: %{ build: String.t(), date: String.t(), revision: String.t(), version: String.t(), otp_release: String.t() }
Elixir構建信息。
返回一個包含 Elixir 版本、它編譯所使用的 Erlang/OTP 發行版、一個簡短的 Git 版本哈希以及它構建的日期和時間的映射。
地圖中的每個值都是一個字符串,它們是
:build
- Elixir 版本、簡短的 Git 版本哈希和它編譯所使用的 Erlang/OTP 發行版:date
- ISO8601 日期和時間的字符串表示形式:otp_release
- 它編譯所使用的 OTP 發行版:revision
- 簡短的 Git 版本哈希。如果在構建時 Git 不可用,則設置為""
:version
- Elixir 版本
不應依賴於每個字段返回的特定格式。而是應使用專用函數,例如 version/0
檢索 Elixir 版本和 otp_release/0
檢索 Erlang/OTP 發行版。
示例
iex> System.build_info()
%{
build: "1.9.0-dev (772a00a0c) (compiled with Erlang/OTP 21)",
date: "2018-12-24T01:09:21Z",
otp_release: "21",
revision: "772a00a0c",
version: "1.9.0-dev"
}
@spec cmd(binary(), [binary()], keyword()) :: {Collectable.t(), exit_status :: non_neg_integer()}
執行帶有參數args
的給定command
。
command
預期是在 PATH 中可用的可執行文件,除非給出絕對路徑。
args
必須是可執行文件將作為其參數接收的二進制列表。這意味著
- 環境變量將不會被插值
- 通配符展開不會發生(除非顯式使用
Path.wildcard/2
) - 參數不需要為了 shell 安全而進行轉義或引用
此函數返回一個包含收集結果和命令退出狀態的元組。
在內部,此函數使用 Port
與外部世界進行交互。但是,如果您計劃運行長時間運行的程序,則端口保證 stdin/stdout 設備將被關閉,但它不會自動終止程序。 Port
模塊的文檔描述了此問題以及可能的解決方案,詳情請參見“殭屍進程”部分。
示例
iex> System.cmd("echo", ["hello"])
{"hello\n", 0}
iex> System.cmd("echo", ["hello"], env: [{"MIX_ENV", "test"}])
{"hello\n", 0}
如果您想將輸出流式傳輸到標準 IO
iex> System.cmd("echo", ["hello"], into: IO.stream())
hello
{%IO.Stream{}, 0}
如果您想讀取行
iex> System.cmd("echo", ["hello\nworld"], into: [], lines: 1024)
{["hello", "world"], 0}
選項
:into
- 將結果注入指定的可收集對象,默認為""
:lines
- (自 v1.15.0 起) 按行而非按字節讀取輸出。它期望在內部緩存的最大字節數(1024 是一個合理的默認值)。無論緩存大小如何,收集對象將被每個已完成的行呼叫,並且不包括 EOL 字符:cd
- 要運行命令的目錄:env
- 包含環境鍵值的元組枚舉體作為二進制。子進程從其父進程(Elixir 應用程序)繼承所有環境變量,除非使用此選項覆蓋或清除。指定nil
的值以清除(取消設置)環境變量,這對於防止傳遞給應用程序的憑證洩漏到子進程中非常有用:arg0
- 設置命令 arg0:stderr_to_stdout
- 當true
時將 stderr 重定向到 stdout:parallelism
- 當true
時,VM 將安排端口任務以提高系統的並行性。如果設置為false
,則 VM 將嘗試立即執行命令,以改善延遲,但並行性會受到損失。默認為false
,並且可以在系統啟動時通過將+spp
標誌傳遞給--erl
來設置。使用:erlang.system_info(:port_parallelism)
檢查是否已啟用。
錯誤原因
如果給出無效的參數,則由 ArgumentError
在 System.cmd/3
中引發。 System.cmd/3
還期望一組嚴格的選項,如果給出未知或無效的選項,則會引發異常。
此外,System.cmd/3
可能因以下 POSIX 原因之一而失敗
:system_limit
- Erlang 模擬器中的所有可用端口都在使用中:enomem
- 沒有足夠的內存來創建該端口:eagain
- 沒有更多可用的操作系統進程:enametoolong
- 外部給定的命令太長:emfile
- 沒有更多可用的文件描述符(用於 Erlang 模擬器運行的操作系統進程):enfile
- 文件表已滿(用於整個操作系統):eacces
- 命令指向的不是可執行文件:enoent
- 命令指向的文件不存在
Shell 指令
如果您想在 shell 內執行一個受信任的命令,包括管道、重定向等等,請檢查 shell/2
。
@spec compiled_endianness() :: :little | :big
返回系統編譯時的字節序。
將時間從時間單位from_unit
轉換為時間單位to_unit
。
結果通過 floor 函數四捨五入。
convert_time_unit/3
接受一個額外的時間單位(除了 time_unit/0
中的單位之外),稱為 :native
。 :native
是 Erlang 運行時系統使用的時間單位。它在運行時啟動時確定,並且在運行時停止之前保持不變,但在同一台機器上下次啟動運行時可能會有所不同。因此,您應該使用此函數將 :native
時間單位轉換為可預測的單位,然後再顯示給人類。
要確定您當前運行時中的 :native
單位代表多少秒,您可以調用此函數將 1 秒轉換為 :native
時間單位: System.convert_time_unit(1, :second, :native)
。
@spec cwd() :: String.t() | nil
當前工作目錄。
返回當前工作目錄,如果不存在則返回 nil
。
@spec cwd!() :: String.t()
當前工作目錄,錯誤時引發異常。
返回當前工作目錄,否則引發 RuntimeError
。
@spec delete_env(String.t()) :: :ok
刪除環境變量。
從環境中刪除變量 varname
。
@spec endianness() :: :little | :big
返回字節序。
返回給定環境變量的值,如果未找到則返回:error
。
如果環境變量 varname
已設置,則返回 {:ok, value}
,其中 value
是一個字符串。如果未設置 varname
,則返回 :error
。
範例
iex> System.fetch_env("PORT")
{:ok, "4000"}
iex> System.fetch_env("NOT_SET")
:error
返回給定環境變量的值,如果未找到則引發異常。
與get_env/1
相同,但在變數未設置時會引發異常,而不是返回nil
。
範例
iex> System.fetch_env!("PORT")
"4000"
iex> System.fetch_env!("NOT_SET")
** (System.EnvError) could not fetch environment variable "NOT_SET" because it is not set
在系統上查找可執行文件。
此函數在Windows和類Unix操作系統上使用環境變數PATH查找具有指定名稱的可執行程序。它還考慮每個操作系統的正確可執行文件擴展名,因此對於Windows,它將嘗試查找帶有.com
、.cmd
或類似擴展名的文件。
返回所有系統環境變量。
返回的值是包含名稱-值對的映射。變量名和它們的值均為字符串。
@spec get_env(String.t(), String.t()) :: String.t()
@spec get_env(String.t(), nil) :: String.t() | nil
返回給定環境變量的值。
環境變數varname
的返回值是一個字符串。如果未設置環境變數,則返回指定的字符串default
,如果未指定則返回nil
。
範例
iex> System.get_env("PORT")
"4000"
iex> System.get_env("NOT_SET")
nil
iex> System.get_env("NOT_SET", "4001")
"4001"
System.pid/0
。
@spec get_pid() :: binary()
Erlang虛擬機進程標識符。
返回當前Erlang虛擬機器的進程標識符,格式為操作系統環境中最常用的格式。
有關更多信息,請參見:os.getpid/0
。
@spec halt(non_neg_integer() | binary() | :abort) :: no_return()
立即停止Erlang運行時系統。
終止Erlang運行時系統,而不正確關閉應用程序和端口。請參見stop/1
以對系統進行謹慎關閉。
status
必須是非負整數、原子:abort
或二進制。
如果是整數,運行時系統將以整數值退出,該值返回給操作系統。
如果是
:abort
,運行時系統將中止並生成核心轉儲,如果在操作系統中啟用了該選項。如果是字符串,將生成一個帶有標語作為狀態的Erlang崩潰轉儲,然後運行時系統以狀態碼1退出。
請注意,在許多平台上,操作系統僅支持狀態碼0-255。
有關更多信息,請參見:erlang.halt/1
。
範例
System.halt(0)
System.halt(1)
System.halt(:abort)
@spec monotonic_time() :: integer()
返回當前單調時間,單位為:native
。
這個時間是單調遞增的,並從一個未指定的時間點開始。這不是嚴格單調遞增的。函數的多個連續調用可能返回相同的值。
由編譯器內聯。
返回以給定時間單位表示的當前單調時間。
這個時間是單調遞增的,並從一個未指定的時間點開始。
@spec no_halt() :: boolean()
檢查系統是否在處理ARGV結束時會停止。
@spec no_halt(boolean()) :: :ok
標記系統是否應在處理ARGV結束時停止。
@spec os_time() :: integer()
返回當前操作系統(OS)時間。
結果以 :native
時間單位返回。
這個時間可能會在沒有限制的情況下向前或向後調整,並且不是單調的。
由編譯器內聯。
返回以給定時間unit
表示的當前操作系統(OS)時間。
這個時間可能會在沒有限制的情況下向前或向後調整,並且不是單調的。
@spec otp_release() :: String.t()
返回Erlang/OTP發行版本號。
@spec pid() :: String.t()
返回當前Erlang運行時系統實例的操作系統PID。
返回一個包含進程的(通常是)數字識別符的字符串。在類 Unix 的操作系統上,這通常是 getpid()
系統調用的返回值。在 Windows 上,使用 GetCurrentProcessId()
系統調用返回的進程 ID。
範例
System.pid()
@spec put_env(Enumerable.t()) :: :ok
設置多個環境變量。
為每個環境變量設置對應於enum
中的每個{key, value}
對的新值。鍵和非空值會自動轉換為 charlists。nil
值會清除給定的鍵。
總的來說,這是一個方便的包裹器,將 put_env/2
和 delete_env/2
進行了封裝,並支援不同的鍵和值格式。
設置環境變量值。
為環境變數 varname
設置新的 value
。
@spec restart() :: :ok
重新啟動Erlang運行時系統中的所有應用程序。
在系統重新啟動所有應用程序之前,所有應用程序都會平滑地停止運行,所有代碼都會被卸載,所有端口都會被關閉。
範例
System.restart()
@spec schedulers() :: pos_integer()
返回VM中計劃程序的數量。
@spec schedulers_online() :: pos_integer()
返回VM中正在線計劃程序的數量。
@spec shell( binary(), keyword() ) :: {Collectable.t(), exit_status :: non_neg_integer()}
在操作系統shell中執行給定的command
。
對於類 Unix 系統,它使用 sh
,而對於 Windows,則使用 cmd
。
請注意
謹慎使用此函數。特別是,絕對不要將不受信任的用戶輸入傳遞給此函數,因為用戶可以通過直接在機器上執行任何代碼來執行 "命令注入攻擊"。一般來說,優先使用
cmd/3
代替此函數。
範例
iex> System.shell("echo hello")
{"hello\n", 0}
如果您想將輸出流式傳輸到標準 IO
iex> System.shell("echo hello", into: IO.stream())
hello
{%IO.Stream{}, 0}
選項
它接受與 cmd/3
相同的選項(除了 arg0
)。它還接受以下獨家選項
:close_stdin
(自 v1.14.1 開始) - 如果在 Unix 系統上應該關閉 stdin,則強制任何等待 stdin 的命令立即終止。默認為 false。
獲取上次異常堆棧跟踪的已棄用機制。
它始終返回一個空列表。
@spec stop(non_neg_integer() | binary()) :: :ok
異步且謹慎地停止Erlang運行時系統。
在系統呼叫 halt/1
之前,所有應用程式都會平滑地停止運行,所有程式碼都會卸載,並且所有埠口都會關閉。
status
必須是一個非負整數或二進制。
如果是整數,運行時系統將以該整數值退出,並將該值返回給操作系統。在許多平台上,操作系統僅支持0到255的狀態碼。
如果是二進制,將產生一個 Erlang 崩潰轉儲,其中狀態作為標語,然後運行時系統將以狀態碼 1 退出。
請注意,此函數是異步的,當調用此函數後,當前進程將繼續執行。如果您想要阻塞當前進程,直到系統有效關閉,您可以調用 Process.sleep(:infinity)
。
範例
System.stop(0)
System.stop(1)
@spec system_time() :: integer()
返回當前系統時間,單位為:native
。
這是 os_time/0
的 VM 觀點。在時間扭曲的情況下,它們可能不匹配,儘管 VM 正在努力對齊它們。這個時間不是單調的。
由編譯器內聯。
返回以給定時間單位表示的當前系統時間。
這是 os_time/0
的 VM 觀點。在時間扭曲的情況下,它們可能不匹配,儘管 VM 正在努力對齊它們。這個時間不是單調的。
@spec time_offset() :: integer()
返回Erlang VM單調時間與Erlang VM系統時間之間的當前時間偏移。
結果以 :native
時間單位返回。
請參閱更多信息,請查看 time_offset/1
。
由編譯器內聯。
返回Erlang VM單調時間與Erlang VM系統時間之間的當前時間偏移。
結果以給定的時間單位 unit
返回。返回的偏移量加上 Erlang 單調時間(例如,使用 monotonic_time/1
獲取的時間)給出對應於該單調時間的 Erlang 系統時間。
@spec tmp_dir() :: String.t() | nil
可寫入的臨時目錄。
返回可寫入的臨時目錄。按以下順序搜索目錄
- 由 TMPDIR 環境變量命名的目錄
- 由 TEMP 環境變量命名的目錄
- 由 TMP 環境變量命名的目錄
- 在 Windows 上為
C:\TMP
,在類 Unix 作業系統上為/tmp
- 作為最後的手段,使用當前工作目錄
如果以上均不可寫,則返回 nil
。
@spec tmp_dir!() :: String.t()
可寫入的臨時目錄,在錯誤時會引發異常。
與 tmp_dir/0
相同,但如果未設置臨時目錄,則引發 RuntimeError
而不是返回 nil
。
@spec trap_signal(signal(), id, (-> :ok)) :: {:ok, id} | {:error, :already_registered} | {:error, :not_sup} when id: term()
捕獲給定的signal
以執行fun
。
避免在庫中設置陷阱
在生產環境中,設置信號陷阱可能會對系統的關機和行為產生重大影響,因此極不建議庫設置自己的陷阱。相反,它們應將用戶重定向到自己配置它們的地方。庫可以自行設置陷阱的唯一情況是在使用 Elixir 作為腳本模式時,例如在
.exs
文件中和通過 Mix 任務。
可以提供一個可選的 給定的 成功時返回 第一次捕獲信號時,它將覆蓋操作系統的默認行為。如果多次捕獲相同的信號,則後續給 默認情況下,Erlang VM 註冊對三個信號的陷阱 因此,如果您向上述信號添加陷阱,則在所有用戶信號之後將執行上述默認行為。 所有信號都從單個進程運行。因此,阻塞 在內部,此功能建立在id
,該 id
唯一標識該函數,否則將自動生成一個唯一的 id
。如果給出了先前註冊的 id
,則此函數將返回一個錯誤元組。可以使用 fun
不接受任何參數,並且必須返回:ok
。{:ok, id}
,如果已經為給定的信號註冊了該 id,則返回{:error, :already_registered}
,如果當前操作系統不支援陷阱存在,則返回{:error, :not_sup}
。trap_signal
的函數將首先執行。換句話說,您可以將每個函數視為附加到信號處理程序的頭部。
實施注意事項
fun
將阻止後續陷阱。在陷阱本身內部也無法添加或刪除陷阱。:os.set_signal/2
之上。當您註冊一個陷阱時,Elixir 自動將其設置為:handle
,一旦所有陷阱都被刪除(除了:sigquit
、:sigterm
和:sigusr1
始終被處理),它將其恢復為:default
。如果您或庫直接調用:os.set_signal/2
,它可能會禁用 Elixir 陷阱(或者 Elixir 可能會覆蓋您的配置)。
@spec unique_integer([:positive | :monotonic]) :: integer()
生成並返回在當前運行時實例中唯一的整數。
“Unique”意味著在當前運行時實例上,使用相同的modifiers
列表調用此函數將不會多次返回相同的整數。
如果modifiers
是[]
,則返回一個獨特的整數(可以是正或負)。其他修飾符可以用來改變返回整數的屬性。
:positive
- 返回的整數保證為正數。:monotonic
- 返回的整數是單調遞增的。這意味著,在同一運行實例中(甚至在不同的進程中),使用:monotonic
修飾符返回的整數始終嚴格小於使用:monotonic
修飾符連續調用返回的整數。
上述列出的所有修飾符都可以組合使用;modifiers
中的重複修飾符將被忽略。
由編譯器內聯。
移除之前註冊的帶有 id
的 signal
。
@spec user_home() :: String.t() | nil
使用者主目錄。
返回用戶的主目錄(跨平台)。
@spec user_home!() :: String.t()
使用者主目錄,在錯誤時引發異常。
與user_home/0
相同,但如果未設置用戶主目錄,則會引發RuntimeError
而不是返回nil
。
@spec version() :: String.t()
Elixir 版本信息。
返回Elixir的版本作為二進制。
@spec wait_until_booted() :: :ok
等待系統啟動。
調用此函數會阻塞,直到處理完所有的ARGV為止。在發布中,這意味著已處理了啟動腳本,然後處理了ARGV。這僅對那些在Elixir之上實現自定義外殼/控制台的人有用。
但是,請務必不要從處理命令行參數的進程內調用此命令,因為這樣做會導致死鎖。