在C#中传递命令行参数

20

我正在尝试将命令行参数传递给一个C#应用程序,但是我无法正确地传递类似于这样的参数

"C:\Documents and Settings\All Users\Start Menu\Programs\App name"

即使我在参数中添加了" ",结果也是一样的。

这里是我的代码:

    public ObjectModel(String[] args)
    {
        if (args.Length == 0) return; //no command line arg.
        //System.Windows.Forms.MessageBox.Show(args.Length.ToString());
        //System.Windows.Forms.MessageBox.Show(args[0]);
        //System.Windows.Forms.MessageBox.Show(args[1]);
        //System.Windows.Forms.MessageBox.Show(args[2]);
        //System.Windows.Forms.MessageBox.Show(args[3]);
        if (args.Length == 3)
        {
            try
            {
                RemoveInstalledFolder(args[0]);
                RemoveUserAccount(args[1]);
                RemoveShortCutFolder(args[2]);
                RemoveRegistryEntry();
            }
            catch (Exception e)
            {
            }
        }
        }

这里是我正在传递的内容:

C:\WINDOWS\Uninstaller.exe  "C:\Program Files\Application name\"  "username"  "C:\Documents and Settings\All Users\Start Menu\Programs\application name"
问题是我可以正确获取前两个参数,但最后一个参数获取为C:\Documents
有帮助吗?

1
你是从哪里开始的?命令行还是另一个程序?如果是后者 - 使用的是什么编程语言? - sharptooth
当您将这样的参数传递到您的应用程序中时会发生什么? - Draco
你能贴出尝试访问参数的代码以及你输入的完整命令行吗?例如 c:\myapp.exe "c:\documents\appname"。 - Robin Day
看起来还好,具体哪里出了问题? - sharptooth
6个回答

28
我刚刚进行了检查并验证了这个问题。让我感到惊讶的是,问题出在第一个参数的最后一个 \ 符号上。
"C:\Program Files\Application name\" <== remove the last '\'

这需要更多的解释,有人有想法吗?我倾向于认为这是一个 Bug。


第二部分,我运行了几个额外的测试。

"X:\\aa aa\\" "X:\\aa aa\" next

变成

X:\\aa aa\
X:\\aa aa" next

通过一些Google搜索,可以从Jon Galloway的博客中获得一些信息,基本规则如下:

  • 反斜杠是转义字符
  • 始终转义引号
  • 只在反斜杠之前遇到引号时才转义反斜杠。

通过删除第一个参数中的 \ 来解决问题。非常感谢。 - Mark
如果你想要那个尾随的反斜杠,你可以再添加一个。也就是说,在命令行中输入"abd\"会得到一个参数"abd"。 - Jim Mischel
2
@Henk:对不起,这里森林/树木太多了。我需要一个假期。 - Jim Mischel
这里有一个GitHub项目,其中包含处理Jon Galloway提到的问题的编码/解码方法:https://github.com/ericpopivker/Command-Line-Encoder - Eric P
在Jon Galloway的帖子中提到了链接到Raymond Chen的帖子。 (https://devblogs.microsoft.com/oldnewthing/20100917-00/?p=12833) - mcdon

5

添加Ian Kemp的答案:

如果您的程序集被命名为"myProg.exe",并且您传递了字符串"C:\Documents and Settings\All Users\Start Menu\Programs\App name",则链接如下:

C:\>myprog.exe "C:\Documents and Settings\All Users\Start Menu\Programs\App name"

字符串"C:\Documents and Settings\All Users\Start Menu\Programs\App name"将在args[0]中。


3
然而,现在的情况是,如果你调用 myprog.exe "c:\one\" "two" "three", 那么 args[0] 将会是 c:\one" two three。你可以试一下! - Nas Banov

1
作为对WWC答案的回应,Jamezor评论说如果第一个字符是引号,他的代码将失败。
为了解决这个问题,你可以用以下代码替换StartToken case:
            if (eps == enumParseState.StartToken)
            {
                if (rWhiteSpace.IsMatch(c.ToString()))
                {
                    //Skip whitespace
                }
                else if (c == '"')
                {
                    eps = enumParseState.InQuote;
                }
                else
                {
                    token.Append(c);
                    eps = enumParseState.InToken;
                }
            }

1

最近我注意到了同样令人烦恼的问题,因此决定编写一个解析器来解析命令行参数数组。

请注意:问题在于.NET命令行参数传递给静态void Main(string[] args)函数时会转义"和\\。这是有意设计的,因为您可能确实想要传递一个带引号或反斜杠的参数。例如:

假设您想将以下内容作为单个参数传递:

-msg:Hey, "Where you at?"

如下所示发送该参数:

sampleapp -msg:"Hey, \"Where you at?\""

这是默认行为下的操作方式。

如果您认为没有必要为程序转义引号或反斜杠,则可以利用自己的解析器解析命令行,如下所示。

例如:

[program].exe "C:\test\" arg1 arg2

args[0]应该是c:\test" arg1 arg2而不是c:\test\,这并不是你期望得到的结果。

下面的函数将参数解析为一个列表,具有这样的简化行为。
注意,使用下面的代码,arg [0] 是程序名称。(调用List.ToArray()将产生的列表转换为字符串数组。)
protected enum enumParseState : int { StartToken, InQuote, InToken };
public static List<String> ManuallyParseCommandLine()
{
    String CommandLineArgs = Environment.CommandLine.ToString();

    Console.WriteLine("Command entered: " + CommandLineArgs);

    List<String> listArgs = new List<String>();

    Regex rWhiteSpace = new Regex("[\\s]");
    StringBuilder token = new StringBuilder();
    enumParseState eps = enumParseState.StartToken;

    for (int i = 0; i < CommandLineArgs.Length; i++)
    {
        char c = CommandLineArgs[i];
    //    Console.WriteLine(c.ToString()  + ", " + eps);
        //Looking for beginning of next token
        if (eps == enumParseState.StartToken)
        {
            if (rWhiteSpace.IsMatch(c.ToString()))
            {
                //Skip whitespace
            }
            else
            {
                token.Append(c);
                eps = enumParseState.InToken;
            }


        }
        else if (eps == enumParseState.InToken)
        {
            if (rWhiteSpace.IsMatch(c.ToString()))
            {
                Console.WriteLine("Token: [" + token.ToString() + "]");
                listArgs.Add(token.ToString().Trim());
                eps = enumParseState.StartToken;

                //Start new token.
                token.Remove(0, token.Length);
            }
            else if (c == '"')
            {
               // token.Append(c);
                eps = enumParseState.InQuote;
            }
            else
            {
                token.Append(c);
                eps = enumParseState.InToken;
            }

        }
            //When in a quote, white space is included in the token
        else if (eps == enumParseState.InQuote)
        {
            if (c == '"')
            {
               // token.Append(c);
                eps = enumParseState.InToken;
            }
            else
            {
                token.Append(c);
                eps = enumParseState.InQuote;
            }

        }


    }
    if (token.ToString() != "")
    {
        listArgs.Add(token.ToString());
        Console.WriteLine("Final Token: " + token.ToString());
    }
    return listArgs;
}

1
如果第一个字符是引号,似乎会出现错误。 - Jamezor

1
补充一下其他人已经说过的,这可能是一个转义问题。你应该用另一个反斜杠来转义你的反斜杠。
应该像这样:
C:\>myprog.exe "C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\App name"

0

问题到底是什么?无论如何,这里有一些通用建议:

确保你的主方法(在Program.cs中)被定义为:

void Main(string[] args)

然后 args 是一个包含命令行参数的数组。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接