Build a Linux CLI app with .NET Core
Animesh Bulusu
Posted on May 14, 2019
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.
Originally posted on my blog @ https://animesh.blog/build-a-linux-cli-app-with-net-core/
Posted on May 14, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.