У меня есть приложение командной строки C#, которое я должен запустить в окнах и под моно в Unix. В какой-то момент я хочу запустить подпроцесс, данный ряд произвольных параматерей, переданных на пути командная строка. Например:
Usage: mycommandline [-args] -- [arbitrary program]
К сожалению, Система. Диагностика. ProcessStartInfo только берет строку для args. Это - проблема для команд, таких как:
./my_commandline myarg1 myarg2 -- grep "a b c" foo.txt
В этом случае argv похож:
argv = {"my_commandline", "myarg1", "myarg2", "--", "grep", "a b c", "foo.txt"}
Обратите внимание, что кавычки вокруг "b c" разделяются оболочкой поэтому, если я просто связываю аргументы для создания строки аргумента для ProcessStartInfo, который я получаю:
args = "my_commandline myarg1 myarg2 -- grep a b c foo.txt"
Который не является тем, что я хочу.
Существует ли простой способ или передать argv, чтобы подобработать запуск под C# ИЛИ преобразовать произвольный argv в строку, которая законна для оболочки Linux и окон?
Любая справка значительно ценилась бы.
Спасибо всем за предложения. В итоге я использовал алгоритм из shquote ( http://www.daemon-systems.org/man/shquote.3.html ).
/**
* Let's assume 'command' contains a collection of strings each of which is an
* argument to our subprocess (it does not include arg0).
*/
string args = "";
string curArg;
foreach (String s in command) {
curArg = s.Replace("'", "'\\''"); // 1.) Replace ' with '\''
curArg = "'"+curArg+"'"; // 2.) Surround with 's
// 3.) Is removal of unnecessary ' pairs. This is non-trivial and unecessary
args += " " + curArg;
}
Я тестировал это только на Linux. Для окон вы можете просто объединить аргументы.
В windowsland это действительно просто ... добавьте лишние кавычки в строку, которую вы передаете объекту System.Diagnostics.ProcessStartInfo.
например. "./my_commandline" "myarg1 myarg2 - grep \" a b c \ "foo.txt"
Вам нужно запустить новый подпроцесс, используя grep
и все аргументы, которые потребуются grep
.
void runProcess(string processName, string args)
{
using (Process p = new Process())
{
ProcessStartInfo info = new ProcessStartInfo(processName);
info.Arguments = args;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
string output = p.StandardOutput.ReadToEnd();
// process output
}
}
затем сделайте вызов runProcess("grep", "a", "b", "c", "foo.txt");
Edit: Обновлена обработка аргументов.
Просто используйте Regex для проверки наличия пробелов в строке и замените исходную строку новой с кавычками:
using System.Text.RegularExpressions;
// ...
for(int i=0; i<argv.Length; i++) {
if (Regex.IsMatch(i, "(\s|\")+")) {
argv[i] = "\"" + argv[i] + "\"";
argv[i].Replace("\"", "\\\"");
}
}
В MSDN есть описание того, как среда выполнения MS Visual C анализирует строку , возвращаемую GetCommandLine ()
в массив argv
.
Возможно, вас заинтересует функция list2cmdline ()
из стандартной библиотеки Python, которая используется модулем Python subprocess
для имитации поведения Unix argv
. в среде Win32.