passing new lines in command line argument? - c#

I loaded up a small console app that simply reads and prints the first command line argument passed to the program to the console.
I want to pass a newline to the argument I tried this:
prog.exe \n --> outputs \n
prog.exe "sfs \n sfff" --> outputs sfs \n sfff
prog.exe "ff \\n ff" --> outputs ff \\n ff
prog .exe "ff \\\\n ff" --> outputs ff \\\\n ff
Is there some other escaping I'm suppose to use? Or is there some function I have to call on args[0] to process escaped characters before outputting it to the console?
To clarify, I'm trying to pass a string to my program that has newlines in it. The outputting to console was being used as a test. I could have just as easily inserted a debug break line and inspect the contents of the variable.

The problem you're having is that the strings you get from the command line are not compiled. When you have string literals in your code they are compiled and this is when escape characters are processed and converted into newlines etc. You will probably have to do something like replacing all instances of "\n" in your input string with a newline character.
Edit:
From here (with minor modifications), this will compile your string using the CSharp compiler thus replacing the escape sequences with the appropriate characters:
public static string ParseString(string input)
{
var provider = new Microsoft.CSharp.CSharpCodeProvider();
var parameters = new System.CodeDom.Compiler.CompilerParameters()
{
GenerateExecutable = false,
GenerateInMemory = true,
};
var code = #"
public class TmpClass
{
public static string GetValue()
{
return """ + input + #""";
}
}";
var compileResult = provider.CompileAssemblyFromSource(parameters, code);
if (compileResult.Errors.HasErrors)
{
throw new ArgumentException(compileResult.Errors.Cast<System.CodeDom.Compiler.CompilerError>().First(e => !e.IsWarning).ErrorText);
}
var asmb = compileResult.CompiledAssembly;
var method = asmb.GetType("TmpClass").GetMethod("GetValue");
return method.Invoke(null, null) as string;
}

Passing line breaks in command line arguments works as expected, actually. Quick test in PowerShell:
PS> ./echoargs "a`nb" b c
arg 1: a
b
arg 2: b
arg 3: c
Now, if what you're trying is to do the same thing in cmd that could prove difficult (and is not really obvious from your question – Process.Start would work, though).

If you pass prog .exe "ff \\\\n ff"
you can replace them from inside your code var s = arg[0[.Replace("\" ,#"\\"); like this

From the windows command line, this is impossible. For security, C# parses user input from the command line as entirely literal. There are no escape characters that will automatically create a new line, unless you write code to go through the string and replace \n with the actual newline character.
If you type in \n into the command line, C# will parse that as \\n.

Related

C# Regex Replacement Not Working

I'm trying to remove new lines from a text file. Opening the text file in notepad doesn't reveal the line breaks I'm trying to remove (it looks like one big wall of text), however when I open the file in sublime, I can see them.
In sublime, I can remove the pattern '\n\n' and then the pattern '\n(?!AAD)' no problem. However, when I run the following code, the resulting text file is unchanged:
public void Format(string fileloc)
{
string str = File.ReadAllText(fileloc);
File.WriteAllText(fileloc + "formatted", Regex.Replace(Regex.Replace(str, "\n\n", ""), "\n(?!AAD)", ""));
}
What am I doing wrong?
If you do not want to spend hours trying to re-adjust the code for various types of linebreaks, here is a generic solution:
string str = File.ReadAllText(fileloc);
File.WriteAllText(fileloc + "formatted",
Regex.Replace(Regex.Replace(str, "(?:\r?\n|\r){2}", ""), "(?:\r?\n|\r)(?!AAD)", "")
);
Details:
A linebreak can be matched with (?:\r?\n|\r): an optional CR followed with a single obligatory LF. To match 2 consecutive linebreaks, a limiting quantifier can be appended - (?:\r?\n|\r){2}.
An empirical solution. Opening your sample file in binary mode revealed that it contains 0x0D characters, which are carriage returns \r. So I came up with this (multiple lines for easier debugging):
public void Format(string fileloc)
{
var str = File.ReadAllText(fileloc);
var firstround = Regex.Replace(str, #"\r\r", "");
var secondround = Regex.Replace(firstround, #"\r(?!AAD)", "");
File.WriteAllText(fileloc + "formatted", secondround);
}
Is this possibly a windows/linux mismatch? Try replacing '\r\n' instead.

Passing Quotation Mark Character (") as C# Console Application Argument

I have a project to demonstrate a program similar to the "echo" command in the MS-DOS Command Line. Here is the code in C#:
using System;
namespace arguments
{
class Program
{
static void Main(string[] args)
{
try
{
switch (args[0])
{
case "/?":
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
Environment.Exit(0);
break;
}
if (args.Length >= 0)
{
string x = "";
foreach (var item in args)
{
x += item.ToString() + " ";
}
Console.WriteLine(Convert.ToString(x)); // this should eliminate vulnerabilities.
}
}
catch
{
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
}
}
}
}
This does a pretty efficient job at doing what it's supposed to do. Then I got into trying to exploit it in any way I could.
In command prompt, I ran arguments.exe ", this is supposed to print out ". But that's not really what happened. I then tried the same with the echo command by running echo ", and it, like it's supposed to, printed out ". This is mind boggling because I wouldn't have even thought this would be a problem. I couldn't get it to pose a great threat, just confused me for a minute.
My question is, is there any way to pass the quotation mark (") as argument to this console application?
Here is a picture to demonstrate it a little bit better: http://prntscr.com/cm9yal
void Main(string[] args)
args array here contains the arguments which have been passed to your application. Because arguments may have spaces they can be surrounded by quotes.
For this reason you won't get the string you have placed as argument. You will also loose any number of spaces between quoted parameters.
If you need the raw command line string, use:
string cmdline = System.Environment.CommandLine;
To be able to get the single quote, you'll need to bypass the default parsing performed by the CLR when populating the args array. You can do this by examining Environment.CommandLine, which in the case you describe above will return something along the lines of:
ConsoleApplication1.exe \"
Note, the argument I passed was simply " (not the escaped variant shown).

Trim not working on null characters

I have a really bizarre problem with trim method. I'm trying to trim a string received from database. Here's my current method:
string debug = row["PLC_ADDR1_RESULT"].ToString();
SPCFileLog.WriteToLog(String.Format("Debug: ${0}${1}",debug,Environment.NewLine));
debug = debug.Trim();
SPCFileLog.WriteToLog(String.Format("Debug2: ${0}${1}", debug, Environment.NewLine));
debug = debug.Replace(" ", "");
SPCFileLog.WriteToLog(String.Format("Debug3: ${0}${1}", debug, Environment.NewLine));
Which produces file output as following:
Debug: $ $
Debug2: $ $
Debug3: $ $
Examining the hex codes in file revealed something interesting. The supposedly empty spaces aren't hex 20 (whitespace), but they are set as 00 (null?)
How our database contains such data is another mystery, but regardless, I need to trim those invalid (?) null characters. How can I do this?
If you just want to remove all null characters from a string, try this:
debug = debug.Replace("\0", string.Empty);
If you only want to remove them from the ends of the string:
debug = debug.Trim('\0');
There's nothing special about null characters, but they aren't considered white space.
String.Trim() just doesn't consider the NUL character (\0) to be whitespace. Ultimately, it calls this function to determine whitespace, which doesn't treat it as such.
Frankly, I think that makes sense. Typically \0 is not whitespace.
#Will Vousden got me on the right track...
https://stackoverflow.com/a/32624301/12157575
--but instead of trying to rewrite or remove the line, I filtered out lines before hitting the StreamReader / StreamWriter that start with the control character in the linq statement:
string ctrlChar = "\0"; // "NUL" in notepad++
// linq statement: "where"
!line.StartsWith(ctrlChar)
// could also easily do "Contains" instead of "StartsWith"
for more context:
internal class Program
{
private static void Main(string[] args)
{
// dbl space writelines
Out.NewLine = "\r\n\r\n";
WriteLine("Starting Parse Mode...");
string inputFilePath = #"C:\_logs\_input";
string outputFilePath = #"C:\_logs\_output\";
string ouputFileName = #"consolidated_logs.txt";
// chars starting lines we don't want to parse
string hashtag = "#"; // logs notes
string whtSpace = " "; // white space char
string ctrlChar = "\0"; // "NUL" in notepad++
try
{
var files =
from file in Directory.EnumerateFiles(inputFilePath, "*.log", SearchOption.TopDirectoryOnly)
from line in File.ReadLines(file)
where !line.StartsWith(hashtag) &&
!line.StartsWith(whtSpace) &&
line != null &&
!string.IsNullOrWhiteSpace(line) &&
!line.StartsWith(ctrlChar) // CTRL CHAR FILTER
select new
{
File = file,
Line = line
};
using (StreamWriter writer = new StreamWriter(outputFilePath + ouputFileName, true))
{
foreach (var f in files)
{
writer.WriteLine($"{f.File},{f.Line}");
WriteLine($"{f.File},{f.Line}"); // see console
}
WriteLine($"{files.Count()} lines found.");
ReadLine(); // keep console open
}
}
catch (UnauthorizedAccessException uAEx)
{
Console.WriteLine(uAEx.Message);
}
catch (PathTooLongException pathEx)
{
Console.WriteLine(pathEx.Message);
}
}
}

C# - Split executable path and arguments into two strings

I've been doing some googling and did not find any solution. The most common case of a path-argument combo has quotes like
"C:\Program Files\example.exe" -argument --argument -argument "argument argument"
"C:\Program Files\example.exe" /argument /argument /argument "argument argument"
They simply go through the entire thing, look for the second quote, then treat everything after that as an argument.
.
The second solution I found (see here) works without quotes yet only works for paths without spaces. See below.
This works: C:\Windows\System32\Sample.exe -args -args -args "argument argument"
This does not work: C:\Program Files\Sample.exe -argument "arg arg" --arg-arg
This works in the same manner. They look for the first space then treat everything after it as an argument, which will not work with some/most programs (the program files folder name has a space).
.
Is there a solution to this? I've tried to use and tweak numerous snippets and even tried to make my own regex statement yet they all failed. Code snippets or even a library would come in handy.
Thanks in advance!
EDIT: The snippets I found as per request
Snippet 1:
char* lpCmdLine = ...;
char* lpArgs = lpCmdLine;
// skip leading spaces
while(isspace(*lpArgs))
lpArgs++;
if(*lpArgs == '\"')
{
// executable is quoted; skip to first space after matching quote
lpArgs++;
int quotes = 1;
while(*lpArgs)
{
if(isspace(*lpArgs) && !quotes)
break;
if(*lpArgs == '\"')
quotes = !quotes;
}
}
else
{
// executable is not quoted; skip to first space
while(*lpArgs && !isspace(*lpArgs))
lpArgs++;
}
// TODO: skip any spaces before the first arg
Source 2: almost everything in here
Source 3: Various shady blogs
You could try a CSV parser like the only onboard in .NET, the VisualBasic.TextFieldParser:
List<string[]> allLineFields = new List<string[]>();
var textStream = new System.IO.StringReader(text);
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(textStream))
{
parser.Delimiters = new string[] { " " };
parser.HasFieldsEnclosedInQuotes = true; // <--- !!!
string[] fields;
while ((fields = parser.ReadFields()) != null)
{
allLineFields.Add(fields);
}
}
With a single string the list contains one String[], the first is the path, the rest are args.
Update: this works with all but your last string because the path is C:\Program Files\Sample.exe. You have to wrap it in quotes, otherwise the space in Program Files splits them into two parts, but that is a known issue with windows paths and scripts.

command line using string.Format() to handle escape characters

Thank for reading my thread.
Here is the command line I like to call within my C# code:
C:\>"D:\fiji-win64\Fiji.app\ImageJ-win64.exe" -eval "run('Bio-Formats','open=D:\\Output\\Untitiled032\\ChanA_0001_0001_0001_0001.tif display_ome-xml')"
This is the exact command I can see from my console window, and it runs and gives me what I need. I want to run this command line from from my C# code, so there is escape character problem I don;t know how to handle
There are two strings I'd like to make them flexible
D:\fiji-win64\Fiji.app\ImageJ-win64.exe
D:\Output\Untitiled032\ChanA_0001_0001_0001_0001.tif
I am wondering how I can use string.Format() to formulate this command line?
This is my current code, it opens the image, but the display_ome-xml did not get called:
string bioformats = "Bio-Formats";
string options = string.Format("open={0} display_ome-xml", fileName.Replace("\\", "\\\\"));
string runCommand = string.Format("run(\"'{0}'\",\"'{1}'\")", bioformats, options);
string fijiCmdText = string.Format("/C \"\"{0}\" -eval {1}", fijiExeFile, runCommand);
where fijiExeFile works fins, it is just the runCommand keeps ignoring the display_ome-xml. Anyone has any suggestions? It is really really confusing. Thanks a lot.
As #Kristian pointed out, # can help here. It also appears that there may be some extra or misplaced \" in the code above. This seems to give the desired output string:
string fijiExeFile = #"D:\fiji-win64\Fiji.app\ImageJ-win64.exe";
string fileName = #"D:\\Output\\Untitiled032\\ChanA_0001_0001_0001_0001.tif";
string bioformats = "Bio-Formats";
string options = string.Format("open={0} display_ome-xml", fileName);
string runCommand = string.Format("run('{0}','{1}')", bioformats, options);
string fijiCmdText = string.Format("\"{0}\" -eval \"{1}\"", fijiExeFile, runCommand);
The easiest way is to use the verbatim string literal.
Just put a # before your string like so:
#"c:\abcd\efgh"
This will disable the backslash escape character
If you need " inside your string, you will have to escape the the quotation marks like so:
#"c:\abcd\efgh.exe ""param1"""
Your example could be:
String.Format(#"""{0}"" -eval ""run('Bio-Formats','open={1} display_ome-xml')""", #"D:\fiji-win64\Fiji.app\ImageJ-win64.exe", #"D:\Output\Untitiled032\ChanA_0001_0001_0001_0001.tif")
or
string p1 = "D:\\fiji-win64\\Fiji.app\\ImageJ-win64.exe";
string p2 = "D:\\Output\\Untitiled032\\ChanA_0001_0001_0001_0001.tif";
String.Format(#"""{0}"" -eval ""run('Bio-Formats','open={1} display_ome-xml')""", p1, p2);

Categories