What is the correct way to pass command line options?

I tried something like this in my mix.exs:

def application do
  [
    applications: [:logger, :httpoison, :poison],
    mod: {Test, []}
  ]
end

In my Test.ex:

defmodule Test do
  use Application

  def start(_mode, _args) do
    System.argv
    |> Test.CLI.main
  end
end

But how do I pass arguments to the start function without “confusing” the mix run script? If I try to mix run --type marc, I get

** (Mix) Could not invoke task "run": 1 error found! --type : Unknown option

Ok, I kind of get that. But then I noticed that if I add some random argument in between like mix run what --type marc, it kind of works: The what gets lost on the way, meaning it is missing from System.argv, which leaves ["--type", "marc"].

You may have noticed: I am somewhat confused. :wink:

What is the correct way to do this besides turning to escript?

It sounds like you want a mix task or an escript.

1 Like

Hello,

You need escript for this job for example in your mix.exs you must pass

escript: [main_module: MyApp]

then in your module define something like this:

defmodule MyApp do
 def main(args) do
  args |> parse_args |> process
 end

def process([]) do
 IO.puts "No arguments given"
end

def process(options) do
 IO.puts "Hello #{options[:name]}"
end

 defp parse_args(args) do
  {options, _, _} = OptionParser.parse(args, switches: [name: :string])
  options
 end
end

finally from the command line:

mix escript.build
$ ./my_app --name=Elixir
2 Likes

Thanks! mix tasks seem to be the closest thing to what I initially intended.

My idea was to avoid the mix escript.build step. Looking at mix tasks, it seems like I would have to start all dependencies manually - so maybe an escript is still the more elegant solution. Thank you for your example!

1 Like

Hello.

I was looking for a thread similar to my original post which I can no longer reply to (Google group got closed): https://groups.google.com/forum/#!topic/elixir-lang-talk/EbVag1bErEk

My original solution was indeed based on escript, but in order to enable “-mode embedded” for code preloading I had to switch away from it and over to building my software with distillery.

distillery builds you scripts to start your application like this: bin/myapp foreground

There is no escript involved.

And I found a solution for commandline arguments: http://erlang.org/doc/man/init.html#get_plain_arguments-0

I filtered, joined, and processed the results and I had all the commandline arguments I needed. Finally solved my problem with commandline arguments.

My final commandline looks like this: bin/myapp foreground --config "something". (You have other options to start the application, of course, like detached or with an attached console.) I then put the parsed results in my applications environment with Application.put_env(:myapp, <key, <value>) and retrieve them later when needed easily.

2 Likes