项目中脚本里大量使用erlang的启动参数配置,今天来学习一下关于erlang的启动参数
官方API
先贴出官方API的地址
前言
erlang启动参数主要有3种,分别是emulator flag, flags和plain arguments。下面我介绍几个常用的并且附上例子
启动时传参
这个用的场景比较多,比如你启动的时候想要传入一个常量配置的参数,他可能不大就几个字符不需要单独创一个文件来存,这时你就可以用它
-extra 要传的参数
[root@feng1 ~]# erl -extra test
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
1> init:get_plain_arguments().
["test"]
当然也可以多个,注意这个额外的传参最后用就行了
[root@feng1 ~]# erl -extra test1 test2 test3
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
1> init:get_plain_arguments().
["test1","test2","test3"]
2>
设置节点名字
这个相信大家学到tcp那章节的时候都用的不少了,长名称和短名称的节点名
-name ××@×× -setcookie ×××
-sname ×××
获取节点名
进入shell后获取节点名
[root@feng1 ~]# erl -sname feng
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
(feng@feng1)1> node().
feng@feng1
(feng@feng1)2> init:get_argument(sname).
{ok,[["feng"]]}
(feng@feng1)3>
当然长名称也一样拿,注意变量名就是
[root@feng1 ~]# erl -name feng666@qq.com -setcookie 666
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
(feng666@qq.com)1> node().
'feng666@qq.com'
(feng666@qq.com)2> init:get_argument(name).
{ok,[["feng666@qq.com"]]}
(feng666@qq.com)3> init:get_argument(sname).
error
(feng666@qq.com)4>
为了方便后面的测试我们先创建一个简单的demo,里面有三个函数分别是0参1参2参
demo
test_start.erl
%%%-------------------------------------------------------------------
%%% @author fengshangjiong
%%% @copyright (C) 2021, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 12. 七月 2021 10:39
%%%-------------------------------------------------------------------
-module(test_start).
-author("fengshangjiong").
%% API
-export([test/0, test/1, test/2]).
test() ->
io:format("test/0").
test(Args) ->
io:format("test/1,A1 is ~w~n", [Args]).
test(Args1, Args2) ->
io:format("test/2,A1 is ~w, A2 is ~w~n", [Args1, Args2]).
启动时编译(-compile)
我们将上面的demo单独放一个文件夹,里面除了他什么都没有
我们用-compile启动参数来编译启动
可以发现他帮我们把这个文件顺手编译了,且编译后的文件与源文件在同一目录下,如果需要同时编译多个模块在后面多加个对应模块名字即可,但是这个好像不是很好用?首先不能指定编译的文件在哪个目录下(一般是ebin),其次编译完也没有进入erlang shell,所以我们一般会用make:all()或者mmake模块来启动,(mmake支持多进程编译),在调用make:all之前需要用到启动时调用函数的方法-eval或者-s或者-run,这里先介绍这三个,在介绍make:all用法
启动时调用-eval
用法
-eval Expr
$ erl -eval 'test_start:test(1)'
Eshell V10.3 (abort with ^G)
test/1,A1 is 1
1>
$ erl -eval 'test_start:test(1,2)'
Eshell V10.3 (abort with ^G)
test/2,A1 is 1, A2 is 2
1>
其他例子
[root@feng1 ~]# erl -eval 'io:format("~w~n",[erlang:now()])'
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
{1626,59179,253130}
Eshell V11.1 (abort with ^G)
1>
启动时调用-s
用法
-s Mod Func Arg1 Args2 …
$ erl -s test_start test 1
test/1,A1 is ['1']
Eshell V10.3 (abort with ^G)
1>
$ erl -s test_start test 1 2
test/1,A1 is ['1','2']
Eshell V10.3 (abort with ^G)
1>
启动时调用-run
用法
-run Mod Func Arg1 Args2 …
$ erl -run test_start test 1
test/1,A1 is [[49]]
Eshell V10.3 (abort with ^G)
1>
$ erl -run test_start test 1 2
test/1,A1 is [[49],[50]]
Eshell V10.3 (abort with ^G)
1>
调用小结
可以发现-s和-run不管传多少个参数进去都被一个list解析,且-s和-run的参数传过去的格式也有细微的差别,想要传完整的参数还得-eval来
启动时编译(make:all)
把刚刚编译成功的test_start.beam删掉我们再试试,这次我们调用make:all/0方法试试给不给我们编译,注意这个方法在erl包中是自带的
用-eval也好-s 也好 -run也行
pc@pc /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ erl -s make all
Recompile: test_start
Eshell V10.3 (abort with ^G)
1>
pc@pc /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ erl -run make all
Recompile: test_start
Eshell V10.3 (abort with ^G)
1>
pc@pc /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ erl -eval 'make:all()'
Eshell V10.3 (abort with ^G)
1> Recompile: test_start
1>
发现都可以编译到的,注意-eval后面的表达式格式就行了
启动时编译(-make)
还有一种就是直接带上-make启动就可以了,也会自动编译当前目录下的erl文件
mmake模块拓展
看到关于并行编译的用法一起放出来,mmake:all/1,发现比make多了一个参数,这个参数表示通过n个workers进程来编译你的代码
使用
erl -eval "case make:files([\"mmake.erl\"], [{outdir, \"ebin\"}]) of error -> halt(1); _ -> ok end"
-eval "case mmake:all(8,[$(MAKE_OPTS)]) of up_to_date -> halt(0); error -> halt(1) end."
(如果没编译成功则退出当前erlshell)
打印启动日志-init_debug
[root@feng1 ~]# erl -init_debug
{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,logger}
{start,application_controller}
{progress,init_kernel_started}
{apply,{application,load,[{application,stdlib,[{description,"ERTS CXC 138 10"},{vsn,"3.13.2"},{id,[]},{modules,[array,base64,beam_lib,binary,c,calendar,dets,dets_server,dets_sup,dets_utils,dets_v9,dict,digraph,digraph_utils,edlin,edlin_expand,epp,eval_bits,erl_abstract_code,erl_anno,erl_bits,erl_compile,erl_error,erl_eval,erl_expand_records,erl_internal,erl_lint,erl_parse,erl_posix_msg,erl_pp,erl_scan,erl_tar,error_logger_file_h,error_logger_tty_h,escript,ets,file_sorter,filelib,filename,gb_trees,gb_sets,gen,gen_event,gen_fsm,gen_server,gen_statem,io,io_lib,io_lib_format,io_lib_fread,io_lib_pretty,lists,log_mf_h,maps,math,ms_transform,orddict,ordsets,otp_internal,pool,proc_lib,proplists,qlc,qlc_pt,queue,rand,random,re,sets,shell,shell_default,shell_docs,slave,sofs,string,supervisor,supervisor_bridge,sys,timer,unicode,unicode_util,uri_string,win32reg,zip]},{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,dets]},{applications,[kernel]},{included_applications,[]},{env,[]},{maxT,infinity},{maxP,infinity}]}]}}
{progress,applications_loaded}
{apply,{application,start_boot,[kernel,permanent]}}
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
{apply,{application,start_boot,[stdlib,permanent]}}
{apply,{c,erlangrc,[]}}
{progress,started}
Eshell V11.1 (abort with ^G)
1>
werl单独窗口启动eshell
这个里面打印的中文不会报错也不会乱码哦
-noshell
跑完自己关了erl进程,适用于调用某模块完成指定逻辑(该参数关闭终端,但依然不会后台运行,有输出时会直接打印到当前屏幕)
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ erl -noshell -eval 'io:format("~w~n",[erlang:now()])'
{1626,60913,474000}
如上面打印完erlang:now不会进入erlang shell
当然你要退出也可以在后面一个函数再调用一个erlang:halt()
$ erl -eval 'io:format("~w~n",[erlang:now()]),halt()'
Eshell V10.3 (abort with ^G)
{1626,61007,911000}
效果一致
-noinput
禁止终端输入
-detached
启动后 后台运行,效果等同于-noshell 和 -noinput 加在一起,一般用-detached
包含目录启动 -pa
比如刚才的test_start.erl我们在同级目录下编译了,如果我们返回上一级目录(没有test_start.beam的目录下)也想要能跑test_start怎么办呢
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ ls
test_start.beam test_start.erl
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc/test
$ cd ../
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc
$ ls
csdn.java lll.erl test test_gen_server.erl
dfs.erl my_bank.erl test.erl test_start.erl
exam1.erl ooo.erl test_demo.app.src tt.hrl
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc
$ erl -s test_start test 1
{"init terminating in do_boot",{undef,[{test_start,test,[['1']],[]},{init,start_em,1,[{file,"init.erl"},{line,1115}]},{init,do_boot,3,[{file,"init.erl"},{line,823}]}]}}
init terminating in do_boot ({undef,[{test_start,test,[[_]],[]},{init,start_em,1,[{_},{_}]},{init,do_boot,3,[{_},{_}]}]})
Crash dump is being written to: erl_crash.dump...done
pc@DESKTOP-QORRTM2 /cygdrive/e/work/sy2020Work/sy/erlang/demo/test_demo/src/etc
$ erl -pa ./test -s test_start test 1
test/1,A1 is ['1']
Eshell V10.3 (abort with ^G)
1>
可以看到在没有的地方直接启动就dump了,但如果把含有beam文件的路径包括进来就好使了,多个路径也是可以的,项目中一般有好几个ebin文件夹也不奇怪
用法
-pa Dir1 Dir2
链接远程节点之前首先需要设置远程节点监听最小值和最大值,以免端口放行问题影响连接
节点端口设置
-inet_dist_listen_min 最小端口
-inet_dist_listen_max 最大端口
只需要在启动时带入即可
erl -inet_dist_listen_min 40000 -inet_dist_listen_max 44000
当然进入以后也是可以查询的
[root@feng1 ~]# erl -inet_dist_listen_min 40000 -inet_dist_listen_max 44000
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
1> init:get_argument(inet_dist_listen_min).
{ok,[["40000"]]}
2> init:get_argument(inet_dist_listen_max).
{ok,[["44000"]]}
3>
远程节点 -remsh
先在本地开两个节点测试一下接管其他erlang控制台的例子
[root@feng1 ~]# erl -detached -name a@127.0.0.1
[root@feng1 ~]# erl -name b@127.0.0.1
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
(b@127.0.0.1)1>
User switch command
--> r 'a@127.0.0.1'
--> j
1 {shell,start,[init]}
2* {'a@127.0.0.1',shell,start,[]}
--> c
Eshell V11.1 (abort with ^G)
(a@127.0.0.1)1> node().
'a@127.0.0.1'
(a@127.0.0.1)2>
User switch command
--> j
1 {shell,start,[init]}
2* {'a@127.0.0.1',shell,start,[]}
--> c
(a@127.0.0.1)2>
User switch command
--> j
1 {shell,start,[init]}
2* {'a@127.0.0.1',shell,start,[]}
--> c 1
(b@127.0.0.1)1> node().
'b@127.0.0.1'
(b@127.0.0.1)2>
先用detached模式启动一个后台erlang控制进程,然后在开另一个erl控制台,通过^G(Ctrl+G)来进入用户切换模式,r链接,j列出当前可用用户列表,c切换。
如果退了一个节点,想把另一个节点detached的节点也关闭怎么办?可以用ps -ef|grep 名字搜一下进程直接kill掉
使用remsh链接
[root@feng1 ~]# erl -detached -name feng_test@127.0.0.1 -setcookie asd
[root@feng1 ~]# erl -setcookie asd -name feng_tt@127.0.0.1 -remsh feng_test@127.0.0.1
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
(feng_test@127.0.0.1)1>
User switch command
--> j
1* {'feng_test@127.0.0.1',shell,start,[]}
-->
可以看到进去以后就是remsh后面的节点了,当然也是可以通过^G模式下切换的
Eshell V11.1 (abort with ^G)
(feng_test@127.0.0.1)1>
User switch command
--> j
1* {'feng_test@127.0.0.1',shell,start,[]}
--> r 'feng_tt@127.0.0.1'
--> j
1 {'feng_test@127.0.0.1',shell,start,[]}
2* {'feng_tt@127.0.0.1',shell,start,[]}
--> c
Eshell V11.1 (abort with ^G)
(feng_tt@127.0.0.1)2> node().
'feng_tt@127.0.0.1'
(feng_tt@127.0.0.1)3>
查看版本-v +v
两种都能看
[root@feng1 ~]# erl +V
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 11.1
[root@feng1 ~]# erl -v
Erlang/OTP 23 [erts-11.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [hipe]
Eshell V11.1 (abort with ^G)
1>
加内存 +P
这个知识进程表所用的内存
用法后面加size
erl +P 204800
附
暂时接触到这些,后面如果有新接触到常用的会持续更新