3

This is my code. The input command line is var1 val1 var2 val2:

var rawCmd = Environment.CommandLine;
// Environment.CommandLine adds the .exe info that I don't want in my command line:
// rawCmd = "path\to\ProjectName.vshost.exe" var1 val1 var2 val2

// A. This correction makes it work, although it is pretty ugly:
var cleanCmd = rawCmd.Split(new string[] { ".exe\" " }, StringSplitOptions.None)[1];

// B. This alternative should be cleaner, but I can't make it work:
var exePath = System.Reflection.Assembly.GetCallingAssembly().Location;
cleanCmd = rawCmd.Replace(string.Format($"\"{exePath}\" "), "");

So to make B work, I should be able to find the .vhost.exe info (which I am not able to find).

But also I would like to know if there is a cleaner way to do all this.


As for the reason why I want to achieve this, here is the explanation (tl;dr: parsing a json from the command line): https://stackoverflow.com/a/36203572/831138

Community
  • 1
  • 1
Xavier Peña
  • 7,399
  • 9
  • 57
  • 99
  • 2
    Why are you not just able to stash the `args` parameter passed to your `Main` method in a convenient location? – Damien_The_Unbeliever Mar 24 '16 at 15:53
  • Why are you dealing with the command line as a single `string`? To my understanding, the arguments are already delivered as an array, as described [here](https://msdn.microsoft.com/en-us/library/cb20e19t.aspx). – Codor Mar 24 '16 at 15:53
  • The reason is the example that I linked at the bottom of the post: http://stackoverflow.com/a/36203572/831138 . The goal is to parse a json from the command line. – Xavier Peña Mar 24 '16 at 15:55
  • Can't you just pipe JSON in like `myExe < file.json` or `echo JSON | myExe`? – Alexei Levenkov Mar 24 '16 at 15:57
  • @AlexeiLevenkov I am inserting the command line from VS2015 in order to debug my code. And then even when the code is in production, given my setup, it would be way easier to just be able to get rid of the exe part of the cmd. – Xavier Peña Mar 24 '16 at 16:01
  • Possible duplicate of [Remove file extension from a file name string](http://stackoverflow.com/questions/7356205/remove-file-extension-from-a-file-name-string) – RoadieRich Mar 24 '16 at 16:07
  • @RoadieRich Sorry but my question has nothing to do with "Remove file extension from a file name string". I don't understand what is going on here. – Xavier Peña Mar 24 '16 at 16:17

6 Answers6

4

Instead of using

var rawCmd = Environment.CommandLine;

You can use:

var rawCmd = Environment.CommandLine;
var argsOnly = rawCmd.Replace("\"" + Environment.GetCommandLineArgs()[0] + "\"", "");

This will return "var1 val1 var2 val2" in your example. And it should work with the JSON example in the other post.

  • But this will remove the quotation marks from the input json, and I won't be able to parse it. – Xavier Peña Mar 24 '16 at 16:21
  • Show me a real example of what you expect your command line to look like when the application is run. –  Mar 24 '16 at 16:24
  • You can take a look at my other post http://stackoverflow.com/a/36203572/831138 . This other post originated my current question, and contains all the details about the example. Bottom line: I want to be able to enter plain json into the command line of vs2015 and be able to get it "unspoiled" within the code. – Xavier Peña Mar 24 '16 at 16:32
  • This edit makes a lot of sense... it is a smart way to get rid of the exe path, without using a convoluted call to get the assembly name. – Xavier Peña Mar 24 '16 at 16:50
4

This only strips the command invocation part, no matter you write it as program, program.exe, .\program, c:program, "c:\Program Files\program", "\Program Files\program.exe", etc. or your path separator.

var exe = Environment.GetCommandLineArgs()[0]; // Command invocation part
var rawCmd = Environment.CommandLine;          // Complete command
var argsOnly = rawCmd.Remove(rawCmd.IndexOf(exe),exe.Length).TrimStart('"').Substring(1);

It will leave double quotes, carets, and spaces between arguments untouched, even spaces at the beginning i.e., just after program name. Note there's an extra space at the beginning, don't ask me why. If that bothers you, remove first character, it should be easy. Hence the final .Substring(1). I define the two variables to make it more readable.

Edit:
Takes account of quoted invocation and the case where the program name string happens to appear as part of an argument (e.g., if your program is me.exe and you run me "Call me Ishmael", .Replace would trim the second me too). Now I also take out that extra space.

cdlvcdlv
  • 952
  • 1
  • 9
  • 22
2

This is a very old question, but as of Windows 10 20H2 and .NET Framework 4.8, all of the above solutions appear to be broken in one way or another (eg. double-quote delimited exe paths).

I needed to remove the exe from Environment.CommandLine in a more generally robust way, so I decided to try a regex based approach. (Then I had 2 problems, lol.) Hope this helps somebody!

    internal static string GetRawCommandLineArgs( )
    {
        // Separate the args from the exe path.. incl handling of dquote-delimited full/relative paths.
        Regex fullCommandLinePattern = new Regex(@"
            ^ #anchor match to start of string
                (?<exe> #capture the executable name; can be dquote-delimited or not
                    (\x22[^\x22]+\x22) #case: dquote-delimited
                    | #or
                    ([^\s]+) #case: no dquotes
                )
                \s* #chomp zero or more whitespace chars, after <exe>
                (?<args>.*) #capture the remainder of the command line
            $ #match all the way to end of string
            ",
            RegexOptions.IgnorePatternWhitespace|
            RegexOptions.ExplicitCapture|
            RegexOptions.CultureInvariant
        );

        Match m = fullCommandLinePattern.Match(Environment.CommandLine);
        if (!m.Success) throw new ApplicationException("Failed to extract command line.");

        // Note: will return empty-string if no args after exe name.
        string commandLineArgs = m.Groups["args"].Value;
        return commandLineArgs;
    }

Testing done:

  • exe paths with/without doublequote
  • args containing doublequotes and also referencing the exe name
  • invoking exe with no args returns empty string

[Edit] Testing NOT done:

  • .NET 5 or any other runtime or OS
0

I have found a way to get the vhost path:

var exePath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, System.AppDomain.CurrentDomain.FriendlyName);

...although I am afraid it could lead to inconsistencies depending on where the code is executed (Debug / production ...). I hope not, I'll have to keep testing.

Xavier Peña
  • 7,399
  • 9
  • 57
  • 99
0

If the number of spaces between elements is not important, you can just Join the argument array, which is split on unquoted space characters, and doesn't contain the executable:

void Main(string[] args)
{
     var cleanCmd = string.Join(" ", args);
     // etc
}
RoadieRich
  • 6,330
  • 3
  • 35
  • 52
0

Actually, the command invocation part is always enclosed in double quotes, even if the path doesn't contain any spaces. And it is always followed by a space character, even if no command line params are specified. So this should be enough in any case:

string args = Environment.CommandLine
    .Substring(Environment.GetCommandLineArgs()[0].Length + 3);

But if you're like me and want to make it 100% waterproof, you can use:

string args = Environment.CommandLine
    .TrimStart('"')
    .Substring(Environment.GetCommandLineArgs()[0].Length)
    .TrimStart('"')
    .TrimStart(' ');
Kim Homann
  • 3,042
  • 1
  • 17
  • 20
  • 1
    "*Actually, the command invocation part is always enclosed in double quotes*" - this is not true, e.g. if the executable is called from the command line, such as `Executable.exe -switch1 -switch2`. – Wai Ha Lee Jan 03 '23 at 16:47