Command Line Subcommands in Erlang

Here’s the translation of the Go code example to Erlang, formatted in Markdown suitable for Hugo:

Our first program demonstrates how to create command-line subcommands with their own set of flags. This is similar to tools like git where different subcommands (e.g., git commit, git push) have their own flags.

-module(command_line_subcommands).
-export([main/1]).

main(Args) ->
    case Args of
        ["foo" | FooArgs] ->
            handle_foo(FooArgs);
        ["bar" | BarArgs] ->
            handle_bar(BarArgs);
        _ ->
            io:format("expected 'foo' or 'bar' subcommands~n"),
            halt(1)
    end.

handle_foo(Args) ->
    {FooOpts, FooArgs} = parse_foo_args(Args),
    io:format("subcommand 'foo'~n"),
    io:format("  enable: ~p~n", [proplists:get_value(enable, FooOpts)]),
    io:format("  name: ~p~n", [proplists:get_value(name, FooOpts)]),
    io:format("  tail: ~p~n", [FooArgs]).

handle_bar(Args) ->
    {BarOpts, BarArgs} = parse_bar_args(Args),
    io:format("subcommand 'bar'~n"),
    io:format("  level: ~p~n", [proplists:get_value(level, BarOpts)]),
    io:format("  tail: ~p~n", [BarArgs]).

parse_foo_args(Args) ->
    parse_foo_args(Args, [], []).

parse_foo_args([], Opts, Rest) ->
    {lists:reverse(Opts), lists:reverse(Rest)};
parse_foo_args(["-enable" | Rest], Opts, Acc) ->
    parse_foo_args(Rest, [{enable, true} | Opts], Acc);
parse_foo_args(["-name", Name | Rest], Opts, Acc) ->
    parse_foo_args(Rest, [{name, Name} | Opts], Acc);
parse_foo_args([Arg | Rest], Opts, Acc) ->
    parse_foo_args(Rest, Opts, [Arg | Acc]).

parse_bar_args(Args) ->
    parse_bar_args(Args, [], []).

parse_bar_args([], Opts, Rest) ->
    {lists:reverse(Opts), lists:reverse(Rest)};
parse_bar_args(["-level", Level | Rest], Opts, Acc) ->
    parse_bar_args(Rest, [{level, list_to_integer(Level)} | Opts], Acc);
parse_bar_args([Arg | Rest], Opts, Acc) ->
    parse_bar_args(Rest, Opts, [Arg | Acc]).

To compile and run the program:

$ erlc command_line_subcommands.erl
$ erl -noshell -s command_line_subcommands main foo -enable -name joe a1 a2 -s init stop
subcommand 'foo'
  enable: true
  name: "joe"
  tail: ["a1","a2"]

$ erl -noshell -s command_line_subcommands main bar -level 8 a1 -s init stop
subcommand 'bar'
  level: 8
  tail: ["a1"]

In this Erlang version, we’ve implemented a basic command-line argument parser to handle subcommands and their respective flags. The main/1 function acts as the entry point and dispatches to the appropriate handler based on the subcommand.

Each subcommand (foo and bar) has its own parsing function to handle its specific flags. The parsing functions return a tuple with the parsed options and the remaining arguments.

Note that Erlang doesn’t have a built-in flag parsing library like Go’s flag package, so we’ve implemented a simple custom parser. In a real-world application, you might want to use a more robust argument parsing library.

This example demonstrates how to structure a command-line application with subcommands in Erlang, providing similar functionality to the original Go example.