This question already has answers here:
C# Console receive input with pipe
(8 answers)
Closed 7 years ago.
I'm trying to read in a text file from the command prompt in C#, via
program.exe < textfile.txt
However, I cannot find the correct way to do this.
So far, I've only been able to pass the path and the filename to string [] args and then opening the file with the StreamReader class. While this is an acceptable alternative, I've been told that the method with "<", which I suppose is a redirection of standard input, offers advantages like not requiring file handling.
Can anyone give some insight into this?
edit: Program.exe is my C# application.
You've got the right idea - the '<' symbol means the Console class reads from the file you specify, instead of reading user input from the console. When you do this, you read from it using the Console class.
The advantages of reading from STDIN is that the user can either run the program as program.exe, and manually type the input the program is expecting, or they can run it as program.exe < input.txt. The only time this is a disadvantage is if you know you will always supply a file, and consider the effort of typing the '<' symbol too much...
In a command prompt the < sign is one of several redirection operators. Specifically, the < sign is the input redirection operator. When you type this: program.exe < textfile.txt, you are telling the command prompt to execute program.exe and read the command input from a file, instead of reading input from the keyboard. In this way, the command prompt basically opens textfile.txt and takes its content and "stuffs it" into the keyboard buffer, so, as far as program.exe is concerned, the input is being read from the keyboard and has no idea you are actually "stuffing" the keyboard buffer with contents from a file.
If your program currently is reading from a file, you will need to modify your program. You no longer want to read from a file and instead read from the keyboard, using commands such as Console.ReadLine or Console.Read or Console.ReadKey.
As far as advantages, the advantages are minimal.
Related
I want to have my C# (Xamarin) program run an EXE or batch (BAT) file. The user will be running my program, and will click on one of several buttons, some of which open Web pages and others of which run external programs. These files will be on the same computer as the one running the main program and don't need greater permissions. The overall program will be in Windows, UWP.
I already have code to pull info from the database saying "the button the user clicked references a program and it's (eg) C:\Tools\MyTool.exe". (Real path more like (C:\Users\Me\source\repos\ProductNameV2\ProductName\ProductName.UWP\Assets\EXE\whatever.exe".) I used a "demo.bat" file containing nothing but echo and pause statements, or references to a built-in Windows program like Notepad or Calc that an ordinary command prompt can recognize without an explicit path (ie. that's part of the recognized system Path). Yes, the real path to the dummy file does exist; I checked. I've also explicitly added files demo.bat and dummy.txt to my C# project.
Here's roughly what I've tried so far to actually run a batch file, or an EXE, or just to try opening a text file. Nothing works.
1)
bool check = await Launcher.CanOpenAsync(#"file:///C:\Tools\demo.bat"); // Returns false.
bool check = await Launcher.CanOpenAsync(#"file:///C:\Tools\dummy.txt"); // Returns true.
await Launcher.OpenAsync(#"file:///C:\Tools\demo.bat") // Seems to do nothing; silently fails.
await Launcher.OpenAsync(#"file:///C:\Tools\dummy.txt") // Same.
2)
Process batchProcess = new Process();
batchProcess.StartInfo.FileName = #"file:///C:\Tools\demo.bat"; // Same result with notepad.exe
batchProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
batchProcess.Start();
batchProcess.WaitForExit();
// Result: "Access is denied" error during Start().
3)
var otherProcessInfo = new ProcessStartInfo(#"file:///C:\Tools\demo.bat")
var otherProcess = Process.Start(otherProcessInfo);
otherProcess.WaitForExit();
otherProcess.Close();
// Result: "The system cannot find the file specified" despite it being the same path as in previous examples.
// Also tried literally using the path C:\Tools\demo.bat, without adding that to the C# project.
// One thing that slightly works is to use:
var otherProcessInfo = new ProcessStartInfo("cmd.exe", "/c echo Hello world!");
// This version opens a window and instantly closes it again. With "/c pause" instead, it opens, saying "press any key to continue".
// Chaining multiple commands with newline or semicolon characters doesn't work as a form of batch file.
So: the only tiny success I've had here is to run cmd.exe, to run a one-line command. I suppose that depending on what the batch file must do, there's some possibility of receiving a string, breaking it into lines, then running cmd.exe using method 3 to call them one at a time. Which is ugly at best.
Is there some better way to do this -- to run a batch file or an EXE from within my program?
EDIT: Yes, I did in fact look at documentation before asking. Why did I use URIs? Because of multiple errors telling me that the simple path strings ("C:\this\that") I was using were in an "Invalid URI format". Using Process.Start("notepad.exe") silently fails, doing nothing. Using a method involving System.Diagnostics.Process (found at How to run external program via a C# program? and yes I saw that before) fails with an error of "Access denied" when using my batch file reference, or silently failing (no window opens) using plain old notepad.exe. I avoided setting Process options that say hide the window.
So to rephrase: Is there a way to make my program run some EXE somewhere on the computer, or to run a batch file that has more than one command in it? What is that way?
Using the data you collected, I was able to run a batch file by doing the following:
var strPathToExeOrBat = System.IO.Path.Combine("C:\\Tools", "demo.bat");
var otherProcessInfo = new ProcessStartInfo("cmd.exe", $"/c call \"{strPathToExeOrBat\"");
var otherProcess = Process.Start(otherProcessInfo);
otherProcess.WaitForExit();
otherProcess.Close();
I also think it would be helpful to review the capabilities of the cmd.exe application.
I found this post to be helpful:
https://stackoverflow.com/questions/515309/what-does-cmd-c-mean#:~:text=%2FC%20Carries%20out%20the%20command%20specified%20by%20the%20string%20and,switches%20by%20typing%20cmd%20%2F%3F%20.
In particular the /k option will leave the window open, if you don't want it to close after running a script.
Thank you very much for your question! It really helped me find the answer to this! (at least for my situation of a .NET MAUI windows app, but MAUI is built off of Xamarin.Forms, so you shouldn't have a problem doing the same thing)
EDIT: Updated to use file path from question and string interpolation with System.IO.Path.Combine for slightly greater cross platform capability
I have a program that has c/c# abilities, and I have python. I want that program to update a text file, almost in milliseconds, and have the python to read that text file in milliseconds as well. How can I go achieve this?
Is it possible for a text file to be updated live by another program and be read live by python? Is there any alternative way to do this instead of relying on text file.
Basically what I want to do is a bunch of computations on live data from that program using python and send back those computations to the program in form of commands.Can a file not be closed and reopened and yet updated in the memory?
If you start the C/C# process from python with subprocess.Popen then your two programs can communicate via the stdin and stdout pipes:
c_program = subprocess.Popen(["ARGS","HERE"],
stdin = subprocess.PIPE, # PIPE is actually just -1
stdout= subprocess.PIPE, # it indicates to create a new pipe
stderr= subprocess.PIPE #not necessary but useful
)
Then you can read the output of the process with:
data = c_program.stdout.read(n) #read n bytes
#or read until newine
line = c_program.stdout.readline()
Note that both of these are blocking methods, although non blocking alternatives exist.
Also note that in python 3 these will return bytes objects, you can convert into a str with the .decode() method.
Then to send input to the process you can simply write to the stdin:
c_program.stdin.write(DATA)
Like the read above, in python 3 this method expects a bytes object. You can use the str.encode method to encode it before writing it to the pipe.
I have extremely limited knowledge of C# but from limited research it seems that you can read data from System.Console.In and write data to System.Console.Out, although if you have written programs in C# that run in a terminal, the same methods used to write data to the screen and read input from the user will work here too. (you can imagine the .stdout as the terminal screen and data python writes to .stdin the user input)
I want to create a command executor like Start > Run. The application has a TextBox and when a user enters a command eg : notepad "C:\test.txt" it should open notepad with this file or %PROGRAMFILES% it should open 'Programs Files' directory.
For %PROGRAMFILES% and other Windows variables I can use Environment.ExpandEnvironmentVariable and get their path and pass to Process.Start
and for notepad, I can split the with space and first part goes in FileName and rest of string goes in Arguments of ProcessStartInfo.
But what I want to know is, how does Start > Run work ? is there something like I can execute the whole command without splitting command-line or expanding the variables ? Maybe with pinvoke ?
To the very best of my knowledge, the run dialog is implemented with a call to ShellExecuteEx. You can achieve the same with Process.Start and UseShellExecute. You do need to expand the environment variables, and split the command into filename and arguments. You already describe how to do that in your question, and, again to the best of my knowledge, there is no programmatic interface to the functionality of the Run dialog.
However, what you can do programmatically is show the Run dialog. Create an instance of the Shell object requesting the IShellDispatch interface, and then call the FileRun method.
I'm executing command lines containing passwords in C#, if I display the optional "Command Line" column in the windows task manager ("Processes" tab) it contains all the arguments including the passwords,
could you think of a way to hide this, like only showing the ".exe" file or something ?
Thanks
If you have control over the program you are calling, you could modify it to read the data from standard input instead of passing the passwords on the command line. This would prevent it from being part of the command line itself, which would "hide" it.
If you cannot change the program, there will be no way to hide the command line used to start the process, as there are Windows API calls that can query this for open processes (which is what is being used by Task Manager).
Well, fist off: In my opinion you should really not do something like passing credentials in a human readable format! Passing a path to a file containing encrypted credentials is not hard to do and much safer.
I don't think that hiding the commandline is even possible. Correct me if I'm wrong.
See: What is the easiest way to encrypt a password when I save it to the registry?
Hey everyone.
I have an exe file that runs a console program that was programmed in C.
during the run of the program the user is asked to enter numbers (using the scanf function).
and the output is being printed to the screen by printf.
The thing is this. I want to make my own txt file with inputs and I want the program to use those inputs.
I also want that the output will be printed to a different txt file - and not in the command window (or in addition to the command windows - I don't care if it's both).
how can I do that, in c#? or can I create a *.bat file that will do that? - that would be best.
Another question:
Is there a way to create a *.bat file that will check if two txt files are the same?
Thanks!
Assuming that the program was written to read from stdin (standard input) and write to stdout (standard output), you should be able to use the following command line:
program.exe < input.txt > output.txt