2012-02-13 69 views
0

獲取可執行文件的名稱。當我從註冊表得到一個完整的命令行字符串,或其他地方,例如:從完整的命令行

mycommand -p -o c:\file\1.txt -r output 

"c:\program files\dir\executable.exe" -options -o1 -o2 

我怎麼能輕鬆地之間的分裂可執行文件和參數?

感謝

回答

3

Windows命令行解析是相當靠不住的,因爲它是由C運行時庫完成的(你可以檢查代碼在Visual Studio中的東西安裝目錄像

  • C:\ Program Files文件(x86)的\微軟的Visual Studio 10.0 \ VC \ CRT \ SRC \ stdargv.c

你的機器上的實際路徑可能會有所不同,當然。而且,如果您沒有使用Visual Studio安裝C運行時源代碼,它將不會是他們的。

我相信這樣的,因爲它是從DOS繼承的,所以它是相當的這些混沌的「邏輯」。

的基本語法是這樣的:

  • A命令行是由空格分隔1個或多個字的序列。

  • 每個字是1或多個以下的序列:BARE_WORD,QUOTED_WORD或ESCAPE_SEQUENCE。單詞由空白或命令行結尾終止。

  • 甲BARE_WORD比反斜槓( '\')其它1個或多個字符,雙引號(序列' 「 ')或空白。

  • 甲QUOTED_WORD由LEAD_IN_QUOTE引入(」' 「),接着是零個或多個以下:

    • 空白
    • ESCAPE_SEQUENCE
    • 裸詞

    並由LEAD_OUT_QUOTE('「')終止。導入和導出報價從引用的單詞中刪除。

  • 一個ESCAPE_SEQUENCE是下列結構之一:

    • 偶數個反斜槓( ' 「 '),後跟一個引號('」')。
      這代表了一系列逃逸的反斜槓,然後是導入/導出報價。每對反斜槓代表一個反斜槓。
    • 奇數個反斜槓,後跟一個引號(''')。
      這表示一系列轉義反斜槓,後面跟着一個文字引號。
    • 反斜槓序列,後面跟着一個引號。
      這表示一系列未轉義的反斜槓,並按原樣傳遞。

這就是它。

命令行中的第一個單詞是命令名稱(例如,可執行文件的名稱/路徑)。嚴格地說,解析命令名稱應該比其他詞語更簡單,因爲它必須表示有效的NTFS文件名稱。然而,這不一定是真實的,取決於誰組成命令行。

下面是一些示例C#代碼,應該以與Windows操作系統相同的方式解析任何給定的命令行,儘管我應該注意,這有而不是經過了全面測試。

方法Parse()返回IEnumerable<string>,其中第一個元素是命令/程序名稱,其餘部分是組成參數的單詞。

class CommandLineParser 
{ 
    char[]  cmd; // source buffer 
    StringBuilder buf; // output buffer 
    int   i; // current position within the source buffer 

    public CommandLineParser() 
    { 
     cmd = null; 
     buf = null; 
     i = -1; 
     return; 
    } 

    public IEnumerable<string> Parse(string commandLine) 
    { 
     cmd = commandLine.ToCharArray(); 
     buf = new StringBuilder(); 
     i = 0; 

     while (i < cmd.Length) 
     { 
      char ch = cmd[i]; 

      if (char.IsWhiteSpace(ch)) { throw new InvalidOperationException(); } 
      else if (ch == '\\') { ParseEscapeSequence(); } 
      else if (ch == '"') { ParseQuotedWord(); } 
      else { ParseBareWord(); } 

      if (i >= cmd.Length || char.IsWhiteSpace(cmd[i])) 
      { 
       string arg = buf.ToString(); 

       yield return arg; 

       buf.Length = 0; 
       ConsumeWhitespace();      
      }     
     }    
    } 

    /// <summary> 
    /// Parse a quoted word 
    /// </summary> 
    private void ParseQuotedWord() 
    { 

     // scan over the lead-in quotation mark w/o adding it to the buffer 
     ++i; 

     // scan the contents of the quoted word into the buffer 
     while (i < cmd.Length && cmd[i] != '"') 
     { 
      char ch = cmd[i]; 
      if (ch == '\\') { ParseEscapeSequence(); } 
      else { buf.Append(ch); ++i; } 
     } 

     // scan over the lead-out quotation mark w/o adding it to the buffer 
     if (i < cmd.Length) 
     { 
      ++i; 
     }    
     return; 
    } 

    /// <summary> 
    /// Parse a bareword 
    /// </summary> 
    private void ParseBareWord() 
    {    
     while (i < cmd.Length) 
     { 
      char ch = cmd[i]; 
      if (char.IsWhiteSpace(ch)) break; // whitespace terminates a bareword 
      else if (ch == '"') break; // lead-in quote starts a quoted word 
      else if (ch == '\\') break; // escape sequence terminates the bareword 

      buf.Append(ch); // otherwise, keep reading this word     

      ++i;     
     }    
     return; 
    } 

    /// <summary> 
    /// Parse an escape sequence of one or more backslashes followed an an optional trailing quotation mark 
    /// </summary> 
    private void ParseEscapeSequence() 
    { 
     //--------------------------------------------------------------------------------------------------------- 
     // The rule is that: 
     // 
     // * An even number of backslashes followed by a quotation mark ('"') means that 
     // - the backslashes are escaped, so half that many get injected into the buffer, and 
     // - the quotation mark is a lead-in/lead-out quotation mark that marks the start of a quoted word 
     //  which does not get added to the buffer. 
     // 
     // * An odd number of backslashes followed by a quotation mark ('"') means that 
     // - the backslashes are escaped, so half that many get injected into the buffer, and 
     // - the quotation mark is escaped. It's a literal quotation mark that also gets injected into the buffer 
     // 
     // * Any number of backslashes that aren't followed by a quotation mark ('"') have no special meaning: 
     // all of them get added to the buffer as-sis. 
     // 
     //--------------------------------------------------------------------------------------------------------- 

     // 
     // scan in the backslashes 
     // 
     int p = i; // start of the escape sequence 
     while (i < cmd.Length && cmd[i] == '\\') 
     { 
      buf.Append('\\'); 
      ++i; 
     } 

     // 
     // if the backslash sequence is followed by a quotation mark, it's an escape sequence 
     // 
     if (i < cmd.Length && cmd[i] == '"') 
     { 
      int n   = (i - p); // find the number of backslashes seen 
      int quotient = n >> 1; // n divide 2 (5 div 2 = 2 , 6 div 2 = 3) 
      int remainder = n & 1; // n modulo 2 (5 mod 2 = 1 , 6 mod 2 = 0) 

      buf.Length -= (quotient + remainder); // remove the unwanted backslashes 

      if (remainder != 0) 
      { 
       // the trailing quotation mark is an escaped, literal quotation mark 
       // add it to the buffer and increment the pointer 
       buf.Append('"'); 
       ++i; 
      }     
     }    
     return; 
    } 

    /// <summary> 
    /// Consume inter-argument whitespace 
    /// </summary> 
    private void ConsumeWhitespace() 
    { 
     while (i < cmd.Length && char.IsWhiteSpace(cmd[i])) 
     { 
      ++i; 
     } 
     return; 
    }   
} 

class Program 
{ 
    static void Main() 
    { 
     CommandLineParser parser  = new CommandLineParser(); 
     string   commandLine = RetrieveUnparsedCommandLine(); 
     int i = 0; 

     IEnumerable<string> args = parser.Parse(commandLine); 
     Console.WriteLine("-------------------"); 
     foreach (string arg in args) 
     { 
      string template = i > 0 ? "argv[0:#0]" : "command"; 
      string label = string.Format(template , i++); 

      Console.WriteLine("{0}: {1}" , label , arg); 

     } 
     Console.WriteLine("-------------------------");    
     return; 
    } 

    static string RetrieveUnparsedCommandLine() 
    { 
     // get the raw command line. Source might be registry, config file, whatever 
     string commandLine = Environment.CommandLine; 
     return commandLine; 
    }  
} 

祝你好運。

1

由於其中包含了可能有效的命令行輸入的字符串:

static string[] SplitArgs(string input) 
{ 
    var args = new List<string>(); 
    var parts = input.Split(' '); 

    for (int ii = 0; ii < parts.Length; ++ii) 
    { 
     // if it starts with a quote, search to the end 
     // NB: this does not handle the case of --x="hello world" 
     // an arguments post processor is required in that case 
     if (parts[ii].StartsWith("\"")) 
     { 
      var builder = new StringBuilder(parts[ii].Substring(0)); 
      while (ii + 1 < parts.Length 
       && !parts[++ii].EndsWith("\"")) 
      { 
       builder.Append(' '); 
      } 

      // if we made it here before the end of the string 
      // it is the end of a quoted argument 
      if (ii < parts.Length) 
       builder.Append(parts[ii].Substring(0, parts[ii].Length - 1)); 

      args.Add(builder.ToString()); 
     } 
     else 
      args.Add(part[ii]); 
    } 

    return args.ToArray(); 
} 
+0

對不起,但我需要一個通用的方法來做到這一點,我的應用程序不是一個ConsoleApplication – 2012-02-13 19:18:25

+0

你可以展開你的意思,它是一個WinForms,WPF等?或者它是一個給定一個字符串或一個字符串數組的庫? – user7116 2012-02-13 19:20:40

+0

我從用戶,文件中獲取字符串,這是完整的命令行,我需要區分可執行文件和參數。 – 2012-02-13 19:22:47