Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to interact with Command Line application

I need to write a component for an application that interacts tightly with a command line application. The command line application asks a series of questions, performs some computations, then terminates (which i need to detect). Essentially, i want to wrap up this interaction in a wrapper class.

Has any one achieved similar in the past? If so, how did you go about it? Did you notice a pattern, or maybe some good build in classes to use? Cheers!

like image 854
NoizWaves Avatar asked Jan 14 '09 11:01

NoizWaves


People also ask

How do you make a console application?

Open Visual Studio, and choose Create a new project in the Start window. In the Create a new project window, select All languages, and then choose C# from the dropdown list. Choose Windows from the All platforms list, and choose Console from the All project types list.

What is a command line program?

The command line (aka Terminal or Command Prompt) refers to a type of program that comes preinstalled with Windows, Linux and Mac computers and allows you to execute commands, run programs and navigate through the folders on your computer.

Is terminal A CLI?

Terminal, or the command line interface (CLI), is considered by many to be the Holy Grail of computer management. At one time the CLI was the only way to accomplish anything on a computer; then, the CLI gave way to the graphical user interface (GUI) as the popularity of PCs increased.


Video Answer


2 Answers

You would need to redirect both the input and output streams, using Process; it is slightly trickier handling both, since you need to be careful that things aren't lost in the buffers (causing deadlock).

  • MSDN : Redirecting input
  • MSDN : Redirecting output
  • Here's a basic alternative example.

You might also want to look at OutputDataReceived for event-based responses.

like image 65
Marc Gravell Avatar answered Oct 05 '22 22:10

Marc Gravell


I get dinged when my responses are just links to elsewhere. I don't see where the link to the C# Corner article helps much.

The question is 10 years old today but it should have been clarified. The question does not specify whether there are line endings (CrLf) at the end of each question. Assuming there are, as in the following:

string Answer;
Console.Out.WriteLine("First question: ");
Answer = Console.In.ReadLine();
Console.Out.WriteLine("Another question: ");
Answer = Console.In.ReadLine();
Console.Out.WriteLine("Final question: ");
Answer = Console.In.ReadLine();

Then the following can be used to respond to it:

class Program
{
    const string FirstQuestion = "First question: ";
    const string SecondQuestion = "Another question: ";
    const string FinalQuestion = "Final question: ";
    static AutoResetEvent Done = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        const string TheProgram = @" ... ";
        Process p = new Process();
        ProcessStartInfo psi = new ProcessStartInfo(TheProgram);
        psi.UseShellExecute = false;
        psi.CreateNoWindow = true;
        psi.RedirectStandardInput = true;
        psi.RedirectStandardOutput = true;
        p.StartInfo = psi;
        Console.WriteLine("Executing " + TheProgram);
        p.Start();
        DoPromptsAsync(p);
        Done.WaitOne();
    }

    private static async Task DoPromptsAsync(Process p)
    {
        StreamWriter sw = p.StandardInput;
        StreamReader sr = p.StandardOutput;
        string Question;
        Question = await sr.ReadLineAsync();
        if (Question != FirstQuestion)
            return;
        sw.WriteLine("First answer");
        Console.WriteLine(Question + "answered");
        Question = await sr.ReadLineAsync();
        if (Question != SecondQuestion)
            return;
        sw.WriteLine("Second answer");
        Console.WriteLine(Question + "answered");
        Question = await sr.ReadLineAsync();
        if (Question != FinalQuestion)
            return;
        sw.WriteLine("Final answer");
        Console.WriteLine(Question + "answered");
        Done.Set();
    }
}

The following works in a WPF application; I used a double-click event to test but this could be used in other WPF events.

const string TheProgram = @" ... ";
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo(TheProgram);
psi.UseShellExecute = false;
//psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
p.StartInfo = psi;
p.Start();
const string FirstQuestion = "First question: ";
const string SecondQuestion = "Another question: ";
const string FinalQuestion = "Final question: ";
StreamWriter sw = p.StandardInput;
StreamReader sr = p.StandardOutput;
string Question;
StringBuilder sb = new StringBuilder("Executing " + TheProgram + "\r\n");
Question = await sr.ReadLineAsync();
if (Question != FirstQuestion)
    return;
sw.WriteLine("First answer");
sb.Append(Question + "answered\r\n");
Question = await sr.ReadLineAsync();
if (Question != SecondQuestion)
    return;
sw.WriteLine("Second answer");
sb.Append(Question + "answered\r\n");
Question = await sr.ReadLineAsync();
if (Question != FinalQuestion)
    return;
sw.WriteLine("Final answer");
sb.Append(Question + "answered\r\n");
ResultBox.Text = sb.ToString();

I think it will be more complicated if there are not line endings after each question.

like image 29
user34660 Avatar answered Oct 05 '22 23:10

user34660