简体   繁体   中英

Implementing a command line interpreter

In terminal or cmd, you can write commands, in which there is a main command and then sub-commands, or arguments and stuff...like this:

cd Desktop\Folder
lst
Format E: /fs:FAT32

I want to create a C# console application that could execute predefined commands like this, but which could also split up main commands and sub-commands, in which some could be optional and some not. I have tried just taking all as string and then splitting it to array and creating if(s) and switch and case s, but it looks really bad and hardly manageable. I'm sure that in the OS's terminal or cmd it's build in another way. Could you help me understand the basic structure of such an application?

Here, have a look at this concept.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SharpConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Welcome to SharpConsole. Type in a command.");

            while (true)
            {
                Console.Write("$ ");
                string command = Console.ReadLine();

                string command_main = command.Split(new char[] { ' ' }).First();
                string[] arguments = command.Split(new char[] { ' ' }).Skip(1).ToArray();
                if (lCommands.ContainsKey(command_main))
                {
                    Action<string[]> function_to_execute = null;
                    lCommands.TryGetValue(command_main, out function_to_execute);
                    function_to_execute(arguments);
                }
                else
                    Console.WriteLine("Command '" + command_main + "' not found");
            }
        }

        private static Dictionary<string, Action<string[]>> lCommands = 
            new Dictionary<string, Action<string[]>>()
            {
                { "help", HelpFunc },
                { "cp" , CopyFunc }
            };

        private static void CopyFunc(string[] obj)
        {
            if (obj.Length != 2) return;
            Console.WriteLine("Copying " + obj[0] + " to " + obj[1]);
        }

        public static void HelpFunc(string[] args)
        {
            Console.WriteLine("===== SOME MEANINGFULL HELP ==== ");
        }
    }
}

The basic idea is to generalize the idea of a command. We have a Dictionary , where the key is a string (the command's name), and the value you get from the dictionary is a function of type Action<string[]> . Any function which has the signature void Function(string[]) can be used as this type. Then, you can set up this dictionary with a bunch of commands and route them to the functions you want. Each of these functions will receive an array of optional arguments. So here, the command "help" will be routed to the HelpFunc() . And the "cp" command eg will receive an array of filenames. The parsing of the command is always the same. We read a line, split it a space. The first string is the program's name, command_main here. If you skip the first string, you'll get an enumeration of all the other subcommands or switches you typed in. Then, a lookup in the dictionary is being done to see if there is such a command. If yes, we get the function and execute it with the arguments. If not, you should display "command not found" or something. All in all, this exercise can be minimized to looking up a function in a dictionary of possible command strings, then executing it. So a possible output is

Welcome to SharpConsole. Type in a command. 
$ help
===== SOME MEANINGFULL HELP ==== 
$ cp file1 otherfile2 
Copying file1 to otherfile2 
$ python --version
Command 'python' not found
$ ...

LXSH

It's a command interpreter similar to CMD or Bash . We've distributed it under MIT license, a shell with some functionalities in C# (.NET Core). You can contribute if you wish on GitHub .

To solve the problem of matching a given token (part of the command line) with a builtin or a command, we use a dictionary.

However, we don't index the programs in the path for the moment. We just combine the name of the program with all the paths in the %PATH% variable.

  1. Capture input
  2. Expand environment variables, expand aliases
  3. Try to match a builtin and run it if there is a match
  4. Try to match with a program in %PATH% / $PATH
  5. Run the program or display error

While you are unlikely to find the internal working of CMD (because it's closed source), you can find easily unix shell (bash, sh, zsh, etc..) information.

Links:

Bash Reference
Zsh Reference
TCSH Reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM