Process.Start () различия между Windows и Linux - PullRequest
0 голосов
/ 10 апреля 2020

Я испытываю некоторые различия в Process.Start() в. NET Core 2.2 проекте. Вы можете найти полный источник в этой сущности: https://gist.github.com/jchristn/5a2a301baedeed787a2e57cd528e46d6

У меня есть метод для запуска процессов:

private static void ExecuteShell(
    string filename, 
    string args, 
    bool useShellExecute,
    bool redirectStdOut,
    bool redirectStdErr,
    out int returnCode, 
    out string consoleOutput)
{
    returnCode = 0;
    consoleOutput = null;

    if (String.IsNullOrEmpty(filename)) throw new ArgumentNullException(nameof(filename));

    // fileName, i.e. "cmd.exe"
    // args, i.e.     "/c dir /w"

    Process process = new Process();
    process.StartInfo.FileName = filename;
    process.StartInfo.Arguments = args;
    process.StartInfo.UseShellExecute = useShellExecute;
    process.StartInfo.RedirectStandardOutput = redirectStdOut;
    process.StartInfo.RedirectStandardError = redirectStdErr;
    process.Start();
    if (process.StartInfo.RedirectStandardOutput) consoleOutput = process.StandardOutput.ReadToEnd();
    process.WaitForExit();
    returnCode = process.ExitCode;
}

И вызывающая сторона выглядит так:

while (true)
{
    try
    {
        Console.WriteLine("");
        Console.WriteLine("Example: cmd.exe /c dir /w");
        Console.Write("Command: ");
        string userInput = Console.ReadLine();
        if (String.IsNullOrEmpty(userInput)) break;

        string[] parts = userInput.Split(new char[] { ' ' }, 2);

        string filename = parts[0];
        string arg = null;
        if (parts.Length > 1) arg = parts[1];

        bool useShellExecute = InputBoolean("  Use shell execute  : ", false);
        bool redirectStdOut =  InputBoolean("  Redirect stdout    : ", false);
        bool redirectStdErr =  InputBoolean("  Redirect stderr    : ", false);

        int returnCode;
        string consoleOutput;

        ExecuteShell(
            filename,
            arg,
            useShellExecute,
            redirectStdOut,
            redirectStdErr,
            out returnCode, out consoleOutput);

        Console.WriteLine("Return code    : " + returnCode);
        Console.WriteLine("Console output : " + consoleOutput);
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception: " + Environment.NewLine + SerializeJson(e, true));
    }
}

Простейший способ воспроизвести более крупную проблему, с которой я столкнулся, заключается в следующем. Предположим, что в файловой системе есть файл, и я хочу type testfile > testfile2, т.е. передать по конвейеру в другой файл.

Вкл. Windows, если я использую cmd.exe /c type testfile > testfile2, он прекрасно работает (с тремя логическими значениями установить false).

т.е.

C:\Code\ExecuteShell\ExecuteShell\bin\Debug\netcoreapp2.2>dotnet ExecuteShell.dll

Example: cmd.exe /c dir /w
Command: cmd.exe /c type testfile > testfile2
  Use shell execute  :  [y/N]?
  Redirect stdout    :  [y/N]?
  Redirect stderr    :  [y/N]?
Return code    : 0
Console output :

Example: cmd.exe /c dir /w
Command:
C:\Code\ExecuteShell\ExecuteShell\bin\Debug\netcoreapp2.2>dir
 Volume in drive C is OS
 Volume Serial Number is 72E2-466A

 Directory of C:\Code\ExecuteShell\ExecuteShell\bin\Debug\netcoreapp2.2

... portions removed ...
04/09/2020  05:41 PM                15 testfile
04/09/2020  05:41 PM                15 testfile2

Когда я пытаюсь это сделать в Ubuntu 14.04, это не получается.

~/code/ExecuteShell/ExecuteShell/bin/Debug/netcoreapp2.2/publish$ dotnet ExecuteShell.dll

Example: cmd.exe /c dir /w
Command: cat testfile > testfile2
  Use shell execute  :  [y/N]?
  Redirect stdout    :  [y/N]?
  Redirect stderr    :  [y/N]?
Hello, world!

cat: >: No such file or directory
cat: testfile2: No such file or directory
Return code    : 1
Console output :

Если я пытаюсь сделать это с useShellExecute установить true, я получаю эту странную xdg-open проблему:

~/code/ExecuteShell/ExecuteShell/bin/Debug/netcoreapp2.2/publish$ dotnet ExecuteShell.dll

Example: cmd.exe /c dir /w
Command: cat testfile > testfile2
  Use shell execute  :  [y/N]? y
  Redirect stdout    :  [y/N]?
  Redirect stderr    :  [y/N]?
xdg-open: unexpected argument 'testfile'
Try 'xdg-open --help' for more information.
Return code    : 1
Console output :

Есть идеи, как заставить это работать?

Ответы [ 2 ]

3 голосов
/ 10 апреля 2020

В этом случае вы путаете использование слова «shell» в контексте Unix (интерпретатор командной строки) с его Windows и C# использованием :

Слово «оболочка» в этом контексте (UseShellExecute) относится к графической оболочке (аналогично оболочке Windows), а не к командным оболочкам (например, bash или sh) и позволяет пользователи запускают графические приложения или открывают документы.

Таким образом, useShellExecute фактически означает, что вы можете дать программе какой-то тип документа и ожидать, что он будет открыт подходящей программой. Это то, что делает xdg-open, поэтому, вероятно, именно поэтому C# вызывает его.

В вашем случае вы хотите выполнить команду sh -c 'cat testfile > testfile2'. Это эквивалент вашего cmd вызова. Тем не менее, ваш код не будет работать, если вы сделаете это сейчас, потому что вы разбиты на пробелы. Таким образом, вы получите аргументы sh, -c, 'cat, testfile, > и testfile2'. В отличие от cmd, который отвечает за собственную обработку аргументов, sh не объединяет свои команды с пробелами, и это не сработает.

Если вы передавали это как массив аргументов, вы хотел бы, чтобы ваши аргументы были sh, -c и cat testfile > testfile2; то есть вся строка, которую вы хотите передать оболочке, должна быть одним полным аргументом.

1 голос
/ 17 апреля 2020

Почему бы не пропустить взаимодействие с оболочкой и использовать вместо него CliWrap ? Это позволяет вам делать то же самое, но не выходя из управляемого кроссплатформенного слоя:

await using var output = File.Create("output.txt");
var command = Cli.Wrap("type").WithArguments("input.txt") | output;
await command.ExecuteAsync();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...