C# Shell Program to Pipe Echo to Text File - c#

I am writing a simple shell program and I have written a few commands for the program. Unfortunately, I also want to allow the shell to pipe an echo command out to a text file and also be able to cat said file and output the contents. The issue I am having is the way that I have written how the echo command works.
public static void Main(string[] args)
{
string command;
do
{
Console.ForegroundColor =
ConsoleColor.DarkGreen;
Console.Write("console > ");
Console.ForegroundColor = ConsoleColor.Gray;
command = Console.ReadLine();
Handle(command);
} while (command != "exit");
}
public static string Handle(string command)
{
if (command.StartsWith("echo "))
{
command = command.Replace("\"", "");
Console.WriteLine(command.Substring(5));
}
if (command.Contains("->"))
{
// logic for echo "text" -> output.txt
}
}
}

You can try something like this that takes the content from before and after the ->. You will have to validate the string of course before you run this
string cmd = #"echo ""text"" -> output.txt";
string text = cmd.Split(" -> ").First().Replace("echo ", "").Replace(#"""", "");
string file = cmd.Split(" -> ").Skip(1).First();

Or, a more general solution (to allow extra commands). First I create a dictionary of commands. The Action<string,string> type represents a delegate to a function that takes two strings as as parameters. The StringComparer.CurrentCultureIgnoreCase means that the case (upper or lower) is ignored when matching:
private static readonly Dictionary<string, Action<string, string>> CommandList =
new Dictionary<string, Action<string, string>>(StringComparer.CurrentCultureIgnoreCase)
{
{"echo", EchoCommand},
{"exit", ExitCommand}
};
Now I have to implement the commands. The echo command is close to what you want to do (I don't bother trying to write to the file, but I get it to the point where you could). The exit command is empty (I just let it fall through). You may want to refactor that behavior.
private static void EchoCommand(string commandText, string file)
{
var fileNote = string.IsNullOrEmpty(file) ? string.Empty : $" ({file})";
Console.WriteLine($"{commandText} {fileNote}");
}
private static void ExitCommand(string commandText, string file)
{
}
Now I need something to parse my command line. This is a brute force hack, but it works. The weird return type is a tuple, an entity that contain many values, in this case three named strings.
static (string command, string text, string file) ParseCommandLine(string commandLine)
{
//find the first space:
var endOfCommandIndex = commandLine.IndexOf(" ");
if (endOfCommandIndex < 0)
{
return (commandLine, string.Empty, null);
}
//otherwise
var command = commandLine.Substring(0, endOfCommandIndex);
var rest = commandLine.Substring(endOfCommandIndex);
var redirectIndex = rest.IndexOf("->");
if (redirectIndex < 0)
{
//use the substring to get rid of the "->"
return (command, rest.Substring(2).Trim(), null);
}
//otherwise (the "+ 2" is to get rid of the "->"
return (command, rest.Substring(0, redirectIndex).Trim(), rest.Substring(redirectIndex + 2).Trim());
}
It bangs away at the command line string and parses it into a Command, some Text and possibly a File to redirect to. I only changed a bit of the core of your Main function. It ends up looking like:
string command, text, file;
do
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write("console > ");
Console.ForegroundColor = ConsoleColor.Gray;
var commandLine = Console.ReadLine();
(command, text, file) = ParseCommandLine(commandLine);
if (CommandList.TryGetValue(command, out var commandAction))
{
commandAction(text, file);
}
else
{
Console.WriteLine("ERROR: Unknown Command");
}
} while (command != "exit");
The TryGetValue call on the dictionary will return true if the command text is in the dictionary. If it returns true, then the commandAction will represent the function to call (so it calls it). If it returns false, then the command is not in the dictionary, so an error is signaled to the user.
And finally, you don't need to put the string to echo in quotes. It just echoes whatever it finds.

Related

merge two programs and using output of 1 as input to another

I am trying to merge two programs, using output of one as an input to other.
Program # 1 ends up writing the output and program 2 wants user input both using console. I don't want result of program 1 to be shown as output but rather used as input so that program 2 doesn't ask for user input.
foreach (var item in result)
{
Console.Write(item);
}
Console.ReadLine();
**end of program 1**
**program 2**
Console.WriteLine("Please, enter numbers");
var numbersStr = Console.ReadLine();
if (!string.IsNullOrEmpty(numbersStr))
{
numbersStr = numbersStr.Trim();
and program continues
It seems like you just need methods. You don't need two programs.
// name this method appropriately!
private static string Program1() {
string retVal = "";
// here goes your program 1
// replace every Console.Write with retVal += ...
// e.g.
foreach (var item in result)
{
retVal += item.ToString();
}
return retVal;
}
// name this properly as well
private static void Program2(string input) {
// program 2 goes here
}
In your Main,
Program2(Program1());
If this is a trivial program you could write the output of the first program to a file or database. And your second program could read from that.
using (var fileWriter = new StreamWriter(pathOfFile))
{
foreach (var item in result)
{
fileWriter.Write(item);
}
}
end of program 1
program 2
Console.WriteLine("Please, enter numbers");
var numbersStr = Console.ReadLine();
var input = File.ReadAllText(pathOfFile)
if (!string.IsNullOrEmpty(input))
{
numbersStr = numbersStr.Trim();
}

How to pass a file path to the program via command line argument

I have 5 files, which I have parsed. They are text files, and I dont know how to pass them to the program via command line arguemnt. I am using visual studio, and C sharp. When I go into Project>Properties>Debug>Command Line Argument> Do I just type in the files? Like File01.txt,File02.txt etc...
The simplest way is to realise that command line arguments are passed to you as an array of strings in your Main(...) method.
class TestClass
{
static void Main(string[] args)
{
// Display the number of command line arguments:
System.Console.WriteLine(args.Length);
foreach(var arg in args)
{
System.Console.WriteLine(arg);
}
}
}
(Broadly from: https://msdn.microsoft.com/en-us/library/acy3edy3.aspx)
Specifically in answer to your question -- yes, in the debug tab, but they need to be space-separated, not comma separated.
If you actually want to open and read the files, you'll need something like (assuming they're text files):
int counter = 0;
string line;
using(var file = new System.IO.StreamReader(arg))
{
while((line = file.ReadLine()) != null)
{
Console.WriteLine (line);
counter++;
}
}
(Broadly from: https://msdn.microsoft.com/en-GB/library/aa287535%28v=vs.71%29.aspx)
In your Main method, you can process your arguments in the following way:
static void Main(string[] args)
{
if (args.Length > 0)
{
foreach (string p in args)
{
Console.WriteLine(p);
}
}
else
{
Console.WriteLine("Empty input parameters");
}
}
When you run your program from command line, you have to use the following syntax:
C:\>yourprogram.exe firstfile.txt secondfile.xls thridfile.dat

Convert from console to string for return [duplicate]

What I really want to do is this
static string Main(string[] args)
but that doesn't work, your only options are void and int. So, What are some different ways to return the string that I need to return to the calling application?
Background
I need to write a console app that is specifically designed to be called from another application
Process.Start("MyCode.exe -Option 12aaa1234");
How can this calling program receive a string returned from that executable?
Research
From what I can tell, at this point in time my only option is to have the calling application attach a listening stream to the Standard Output stream of the process before starting it, and send the "return" using Console.Out.Write from inside my executable. Is this in fact the ONLY way to do this, or is there something different/better I can use?
Is this in fact the ONLY way to do this, or is there something different/better I can use?
This isn't the only way to do this, but it is the most common.
The other options would involve some form of interprocess communication, which is likely going to be significantly more development effort for a single string.
Note that, if the calling application is a .NET application, and you have control over both applications, it might make more sense to just write a class library instead of a console application. This would allow you to keep the code completely separate, but have the executable "call into" your library to get the string data.
Idea 1:
Using MyCode.exe, create an encrypted text file, which is saved in a specified path, which can then be decrypted in the current app and read.
In the app: "MyCode.exe", add this code:
public void ReturnToOther()
{
string ToReturn = "MyString";
System.IO.File.WriteAllText("Path", Encrypt(ToReturn));
}
public String Encrypt(string ToEncrypt)
{
string Encrypted = null
char[] Array = ToEncrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Encrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) + 15));
}
return Encrypted;
}
In the app you are making now:
public void GetString()
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
}
// If you want to keep this running before the file exists, use this:
/*
public void GetString()
{
for(int i = 0; i > -1; ++i)
{
if(System.IO.File.Exists("Path"))
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
break;
}
else
{
//Do something if you want
}
}
} */
public String Decrypt(string ToDecrypt)
{
string Decrypted = null
char[] Array = ToDecrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Decrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) - 15));
}
return Decrypted;
}
Idea 2:
Use TCP to upload the string to a port, e.g. LocalHost (127.0.0.1), and then receive the string on the app you are developing, using a TCP Listener
An article on TCP - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Hope this helps :)
EDIT:
Have a look at Sockets too: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx

How can I quickly identify the path and the search pattern in C:\Users\Admin\Samples\*.pdf?

I would like to create a simple copy console application (I know copy already exists in DOS). Exactly like the DOS copy command I would like to be able to execute my copy application with two simple arguments:
copy C:\Users\Admin\Samples\*.pdf C:\
Input path and search pattern
Ouput path
In my code I use this
static void Main(string[] args)
{
string input;
string output;
var options = new Options();
ICommandLineParser parser = new CommandLineParser();
if (parser.ParseArguments(args, options))
{
input = options.Argument[0];
output = options.Argument[1];
// Get file list
String directory = Path.GetDirectoryName(input);
String[] files = Directory.GetFiles(directory, /* ??? */);
// To be continued...
}
else
{
System.Console.WriteLine("Erreur");
System.Console.ReadKey();
}
}
How can I easely retrieve my search pattern? Is beter way to do this?
Try this:
string extension = System.IO.Path.GetExtension(input);
string inputDirectory = System.IO.Path.GetDirectoryName(input);
I think this is what you wanted.
To get the path, or the file, of the input parameter, you can use the following:
Path.GetFileName(input);

Is it possible to read unknown number of lines from console in C#?

There is a function, which can read a single line from the console input (Console.ReadLine()), but I wish to read or some arbitrary number of lines, which is unknown at compile time.
Of course it is. Just use just read a single line (using ReadLine() or whatever else you please) at a time within either a for loop (if you know at the beginning of reading how many lines you need) or within a while loop (if you want to stop reading when you reach EOF or a certain input).
EDIT:
Sure:
while ((line = Console.ReadLine()) != null) {
// Do whatever you want here with line
}
Some of the other answers here loop until a null line is encountered while others expect the user to type something special like "EXIT". Keep in mind that reading from the console could be either a person typing or a redirected input file:
myprog.exe < somefile.txt
In the case of redirected input Console.ReadLine() would return null when it hits the end of the file. In the case of a user running the program interactively they'd have to know to how to enter the end of file character (Ctrl+Z followed by enter or F6 followed by enter). If it is an interactive user you might need to let them know how to signal the end of input.
simple example:
class Program
{
static void Main()
{
CountLinesInFile("test.txt"); // sample input in file format
}
static long CountLinesInFile(string f)
{
long count = 0;
using (StreamReader r = new StreamReader(f))
{
string line;
while ((line = r.ReadLine()) != null)
{
count++;
}
}
return count;
}
}
The best thing to do here is use a loop:
string input;
Console.WriteLine("Input your text (type EXIT to terminate): ");
input = Console.ReadLine();
while (input.ToUpper() != "EXIT")
{
// do something with input
Console.WriteLine("Input your text(type EXIT to terminate): ");
input = Console.ReadLine();
}
Or you could do something like this:
string input;
do
{
Console.WriteLine("Input your text (type EXIT to terminate): ");
input = Console.ReadLine();
if (input.ToUpper() != "EXIT")
{
// do something with the input
}
} while (input.ToUpper() != "EXIT");

Categories

Resources