Build a Linux CLI app with .NET Core
Tags: dotnetcore, linux
Published: 2019-05-14 15:37:24

---
title: Build a Linux CLI app with .NET Core
published: true
description: Create a basic command line application with .NET Core on Linux
tags: dotnetcore, linux
canonical_url: https://animesh.blog/build-a-linux-cli-app-with-net-core/
---

Being a developer and a geek for as long as I can remember, command line tools have always fascinated me. They are relatively easy to create and use than a web app or a desktop app. 

In this post, we will explore how to build a simple command line tool on Linux using .NET Core.

Create a new console app using the `dotnet` cli.

```
$ dotnet new console -o netcore-test-cli
$ code netcore-test-cli
```
Most command line tools do take user input and perform actions as based on these inputs. 

These inputs come into the `Main` function during runtime by the way of the `string[] args` parameter. We could simply parse the arguments and their values from the string array `args`, but this is a tedious thing for us to do. 

Fortunately, there are many open source libraries to help us do this. One such library is `CommandLineParser`. I have used it in a couple of projects and like it.

Let us add this command line parsing library to the project.

```
$ dotnet add package CommandLineParser
```

To get started with CommandLineParser, first we need to specify the types and names of the arguments in the form of an `Options` class. Then we need to use a Parser instance to parse the arguments provided.

```
var result = Parser.Default.ParseArguments<Options>(args)
```

On successful parsing, we get back a `Parsed<Options>` type. Otherwise, we get back a `NotParsed<T>` type which is an error collection of type `IEnumerable<Error>`.

The prescribed way to do this is to use the `WithParsed` and `WithNotParsed` extension methods which take on the respective parsed types and pass the parsed options to further processing.

```
static void Main(string[] args)
{
    Parser.Default.ParseArguments<Options>(args)
        .WithParsed<Options>(options => ProcessOptions(options))
        .WithNotParsed<Options>(options => HandleErrors(options));
}
```

For the sake of simplicity, let us define two options, `Count` and `Name`, as follows. 

```
class Options
{
    [Option('c', "count", HelpText="The count variable")]
    public int Count { get; set; }

    [Option(HelpText="Name for greeting")]
    public string Name { get; set; }
}
```

We need to specify the `[Option]` attribute on our two properties. This lets `CommandLineParser` know which properties are valid for parsing against the user input. Notice that `Count` option has `c` for its `ShortName` and `count` for its `LongName`. This lets you specify count input as either `-c 10` or `--count 10`.

Let us just take the `Count` option to generate a sum of all whole numbers upto `Count` and display a exit message if the `Name` option is specified.

```
private static void ProcessOptions(Options options)
{
    int sum = 0;
    for (int i = 1; i <= options.Count; i++)
    {
        sum = sum + i;
    }
    Console.WriteLine($"Sum: {sum}");

    if(!string.IsNullOrEmpty(options.Name))
        Console.WriteLine($"Bye, {options.Name}");
}
```

To run the program use, `dotnet run` command.
```
$ dotnet run -- --count 10 --name=animesh
Sum: 55
Bye, animesh
```

If you want to run the compiled program directly, you can run `dotnet` command and pass the name of the output dll.
```
$ dotnet bin/Debug/netcoreapp2.2/netcore-test-cli.dll -c 123
Sum: 7626
```

To make it a proper Linux executable, we need to publish the program with appropriate runtime identifier.

```
$ dotnet publish -c 'release' -r 'linux-x64'

Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 55.08 ms for /home/animesh/projects/lucubrations/netcore-test-cli/netcore-test-cli.csproj.
  netcore-test-cli -> /home/animesh/projects/lucubrations/netcore-test-cli/bin/release/netcoreapp2.2/linux-x64/netcore-test-cli.dll
  netcore-test-cli -> /home/animesh/projects/lucubrations/netcore-test-cli/bin/release/netcoreapp2.2/linux-x64/publish/
```

This publishes the program to folder `bin/Release/netcoreapp2.2/linux-x64`. Check it out.

```
$ ll bin/Release/netcoreapp2.2/linux-x64

total 1552
-rwxrw-rw- 1 animesh animesh 692128 Jan 18 03:54 libhostfxr.so
-rwxrw-rw- 1 animesh animesh 712624 Jan 18 03:54 libhostpolicy.so
-rwxrw-rw- 1 animesh animesh 106912 Mar  9 15:29 netcore-test-cli
-rw-r--r-- 1 animesh animesh  37340 Mar  9 15:29 netcore-test-cli.deps.json
-rw-r--r-- 1 animesh animesh   5632 Mar  9 15:29 netcore-test-cli.dll
-rw-r--r-- 1 animesh animesh    928 Mar  9 15:29 netcore-test-cli.pdb
-rw-r--r-- 1 animesh animesh    206 Mar  9 15:29 netcore-test-cli.runtimeconfig.dev.json
-rw-r--r-- 1 animesh animesh     26 Mar  9 15:29 netcore-test-cli.runtimeconfig.json
drwxr-xr-x 2 animesh animesh  12288 Mar  9 15:29 publish
```

Notice the file attributes on the third item `netcore-test-cli` in the directory listing above. It has file attributes `-rwxrw-rw-`, which means it is a Linux executable. This became possible as we specified the `linux-x64` runtime identifier. 

We can run the executable just as before.

```
$ cd bin/Release/netcoreapp2.2/linux-x64

$ ./netcore-test-cli 

Sum: 0

$ ./netcore-test-cli -c 100

Sum: 5050
```

Both parameters specified:
```
$ ./netcore-test-cli -c 1000 --name animesh

Sum: 500500
Bye, animesh
```

Specifying the `--help` option shows all possible options for user input:
```
$ ./netcore-test-cli --help

netcore-test-cli 1.0.0
Copyright (C) 2019 netcore-test-cli

  -c, --count    The count variable

  --name         Name for greeting

  --help         Display this help screen.

  --version      Display version information.

```

That's the end of this post. We have seen how to build a basic command line application with .NET Core.

All code for this post is available on my [gitlab repository](https://gitlab.com/lucubrations/netcore-test-cli).

---

_Originally posted on my blog @ https://animesh.blog/build-a-linux-cli-app-with-net-core/_