Erlang command line - erlang

I need to pass two arguments to my Erlang code. it is working fine in the Erlang shell.
2> crop:fall_velocity(x,23).
21.23205124334434
but how should i run the Erlang code without the Erlang shell. like normal python,c programs.
./program_name (not passing $1 $2 arguments).
I was trying this
erl -noshell -s crop fall_velocity(x,20) -s init stop
But it is giving unexpected token error.

As documentation states, the -s passes all parameters supplied as just one list of atoms and -run does the same but as a list of strings. If you want to call arbitrary function with arbitrary parameter count and types you should use -eval:
$ erl -noshell -eval 'io:format("test\n",[]),init:stop()'
test
$

You can use escript to run Erlang scripts from the command line. In that script you should create a main function which takes an array of arguments as a string.
#!/usr/bin/env escript
main(Args) ->
io:format("Printing arguments:~n"),
lists:foreach(fun(Arg) -> io:format("Got argument: ~p~n", [Arg]) end,Args).
Output:
./escripter.erl hi what is your name 5 6 7 9
Printing arguments:
Got argument: "hi"
Got argument: "what"
Got argument: "is"
Got argument: "your"
Got argument: "name"
Got argument: "5"
Got argument: "6"
Got argument: "7"
Got argument: "9"

Related

Using os:cmd to in escript to start Erlang application fails.

I have an Erlang application named tb that runs fine from Erlang command line by doing application:start(tb). Whereas when I try to invoke the same application from inside escript using os:cmd, the application doesn't seem to run. When i do a 'ps | grep beam', I see the beam.smp process running. But the application is not generating any output.What might be the problem? Is there a better way to start another erlang VM from inside escript?
Here's the code snippet:
net_kernel:start([tb_escript, shortnames]),
read_config_file(FName),
Cookie = get(cookie),
Node = get(node),
N = io_lib:format("~p",[Node]),
lists:flatten(N),
C = io_lib:format("~p",[Cookie]),
lists:flatten(C),
EBIN = "~/tb/ebin",
erlang:set_cookie(tb_escript,Cookie),
os:cmd("erl -pa " ++ EBIN ++ " -sname " ++ N ++ " -detached " ++ " -setcookie " ++ C ++ " -s application start tb").
This happens because the args flag to -s wraps the arguments in a list and passes that to module:function/1. -s application start tb will execute application:start([tb]), which would return {error,{bad_application,[ssl]}}. As this is just a normal return value, no error is printed by erl.
From the erl documentation:
-s Mod [Func [Arg1, Arg2, ...]](init flag)
Makes init call the specified function. Func defaults to start. If no arguments are provided, the function is assumed to be of arity 0. Otherwise it is assumed to be of arity 1, taking the list [Arg1,Arg2,...] as argument. All arguments are passed as atoms.
There are two ways to solve this:
Use -eval "application:start(tb)", as you already mentioned in a comment.
Add a start/0 (if not already present) function to tb which calls application:start(tb), and then pass just -s tb to erl. -s with a single argument will call module:start().

How can I pass command-line arguments to a Erlang program?

I'm working on a Erlang. How can I pass command line parameters to it?
Program File-
-module(program).
-export([main/0]).
main() ->
io:fwrite("Hello, world!\n").
Compilation Command:
erlc Program.erl
Execution Command-
erl -noshell -s program main -s init stop
I need to pass arguments through execution command and want to access them inside main written in program's main.
$ cat program.erl
-module(program).
-export([main/1]).
main(Args) ->
io:format("Args: ~p\n", [Args]).
$ erlc program.erl
$ erl -noshell -s program main foo bar -s init stop
Args: [foo,bar]
$ erl -noshell -run program main foo bar -s init stop
Args: ["foo","bar"]
It is documented in erl man page.
I would recommend using escript for this purpose because it has a simpler invocation.
These are not really commandline-parameters, but if you want to use environment-variables, the os-module might help. os:getenv() gives you a list of all environment variables. os:getenv(Var) gives you the value of the variable as a string, or returns false if Var is not an environment-variable.
These env-variables should be set before you start the application.
I always use an idiom like this to start (on a bash-shell):
export PORT=8080 && erl -noshell -s program main
If you want "named" argument, with possible default values, you can use this command line (from a toy appli I made):
erl -pa "./ebin" -s lavie -noshell -detach -width 100 -height 80 -zoom 6
lavie:start does nothing more than starting an erlang application:
-module (lavie).
-export ([start/0]).
start() -> application:start(lavie).
which in turn start the application where I defined default value for parameters, here is the app.src (rebar build):
{application, lavie,
[
{description, "Le jeu de la vie selon Conway"},
{vsn, "1.3.0"},
{registered, [lavie_sup,lavie_wx,lavie_fsm,lavie_server,rule_wx]},
{applications, [
kernel,
stdlib
]},
{mod, { lavie_app, [200,50,2]}}, %% with default parameters
{env, []}
]}.
then, in the application code, you can use init:get_argument/1 to get the value associated to each option if it was defined in the command line.
-module(lavie_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, [W1,H1,Z1]) ->
W = get(width,W1),
H = get(height,H1),
Z = get(zoom,Z1),
lavie_sup:start_link([W,H,Z]).
stop(_State) ->
% init:stop().
ok.
get(Name,Def) ->
case init:get_argument(Name) of
{ok,[[L]]} -> list_to_integer(L);
_ -> Def
end.
Definitively more complex than #Hynek proposal, but it gives you more flexibility, and I find the command line less opaque.

Limit of argument size of a command (for ex: in grep "$some_argument_size" filename)

I'm running a shell script and line# 15 is:
grep "$var1$var2" somefilewithonly10000lines_letsay
and getting an error:
line 15: /bin/grep: Argument list too long
What's the limit for the grep command's pattern? -- which when I reach, gives me the above error message.
THe following will tell the limit. Thanks Cyrus.
$ getconf ARG_MAX
More info: http://www.in-ulm.de/~mascheck/various/argmax/

No output or error message from Erlang shell

Sometimes when i try to run a command in the Erlang shell (for example calling a function from a module etc) the shell doesn't give any output or error message and just returns. I am sure that i give the command in the right shape (with a dot at the end etc).
To solve this i have to give the following commands in the shell:
'. or ".
And then the shell prints a long atom or what ever and then after that i can run my original command correctly.
Does anyone have seen a same issue? And what is the reason for this?
This looks like there were an initial ' or " in the command line. So the shell is waiting for the second ' or " which closes the atom or string declaration. It prints the evaluation result and is now ready for the next command.
Look at this example in the console (started with erl):
Eshell V10.6.2 (abort with ^G)
1> io:format("Hello world!").
Hello world!ok
2> io:format("Hello world! ).
2> ".
* 2: syntax error before: '.'

run eunit test from console using erl -noshell

I wanted to run the following eunit test command from console
eunit:test([test_module, [verbose]).
I tried this, but seems not working
erl -noshell -pa ./ebin -s eunit test test_module verbose -init stop
~/uid_server$erl -noshell -pa ./ebin -s eunit test test_module verbose -init stop
undefined
*** test module not found ***
::test_module
=======================================================
Failed: 0. Skipped: 0. Passed: 0.
One or more tests were cancelled.
Do you know how to pass not a simple arguments properly from console?
Your parameters look wrong. This should work:
erl -noshell -pa ebin -eval "eunit:test(test_module, [verbose])" -s init stop
-s can only run functions without arguments by specifying the module and function name (for example init and stop to execute init:stop()).
You can also pass one list to a function of arity 1 like this:
-s foo bar a b c
would call
foo:bar([a,b,c])
All the parameters are passed as a list of atoms only (even when you try to use some other characters, such as numbers, they are converted to atoms).
So since you want to pass two params and not only atoms if you want to run eunit:test/2 you'd have to use -eval which takes a string containing Erlang code as an argument. All -eval and -s functions are executed sequentially in the order they are defined.
Also, make sure you have your test code in ./ebin as well (otherwise write -pa ebin test_ebin where test_ebin is where your test code is).
You can also use rebar...
Get rebar by cd'ing to your project directory and typing the following:
curl http://cloud.github.com/downloads/basho/rebar/rebar -o rebar
chmod u+x rebar
Add the following to your module under test, right after last export:
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
Next, add your tests at the bottom of your module, wrapped in an ifdef like so:
-ifdef(TEST).
simple_test() ->
?assertNot(true).
-endif.
Lastly, run rebar from your shell like so:
./rebar compile eunit
you can try quote parameters instead of listing.
erl -noshell -pa ./ebin -s eunit test "test_module verbose" -init stop
More than eight years passed since the question, but there's still a nice solution not mentioned in the previous answers.
Once you are using EUnit, you can leverage from some of it's "automagic" features. One of them is an automatic export of the test/0 function, containing all the tests for the module.
So, if you are writing your tests alongside with the source code in the same module, all you have to do is:
$ erl -noshell -run your_module test -run init stop
If you are writing the tests in a separated, dependent module (as you should), you have to point to that module:
$ erl -noshell -run your_module_tests test -run init stop
All this will work fine, but the test won't be run in verbose mode as the OP required, but this is simple to solve with the EUNIT environment variable set to verbose.
Final version:
$ EUNIT=verbose erl -noshell -run your_module_tests test -run init stop
Have fun with Erlang and EUnit!
I use this script: https://github.com/lafka/dotconfig/blob/master/bin/eunit-module to run eunit on specific modules.
Example:
eunit-module <module> src ebin -I deps
That will do a couple of things:
Arg #2 is the directory where .erl resides
Arg #3 is the directory to output the compiled .beam
Arg #4++ is all the additional paths to add to your code path
Using -I specifies additional code paths AND where to look for files referenced with -include_lib

Resources