c# - Windows 和 Linux 的 Process.Start() 区别
问题描述
我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
)。
IE
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
set to 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 :
知道如何进行这项工作吗?
解决方案
在这种情况下,您会将“shell”一词在其 Unix 上下文(命令行解释器)中的使用与它的 Windows 和C# 使用混淆:
在此上下文中,“shell”一词 (UseShellExecute) 指的是图形 shell(类似于 Windows shell)而不是命令 shell(例如 bash 或 sh),它允许用户启动图形应用程序或打开文档。
所以useShellExecute
实际上意味着你可以给程序一个某种类型的文档,并期望它被合适的程序打开。就是这样xdg-open
做的,所以这可能就是 C# 调用它的原因。
在您的情况下,您要运行的命令是sh -c 'cat testfile > testfile2'
. 这相当于你的cmd
调用。但是,如果您现在这样做,您的代码将无法工作,因为您在空格上进行了拆分。所以你最终会得到参数sh
, -c
, 'cat
, testfile
, >
, 和testfile2'
。不同cmd
的是,它负责自己的参数处理,sh
不会将其命令与空格连接起来,这是行不通的。
如果您将其作为参数数组传递,您希望您的参数为sh
,-c
和cat testfile > testfile2
; 也就是说,您要传递给 shell 的整个字符串应该是一个完整的参数。
推荐阅读
- python - 当小数> = 1时,pandas / numpy round() 如何工作?
- kotlin - Kotlin:用扩展属性设置器覆盖自我
- java - 如何使用 Apache HttpAsyncClient 发布非 JSON 请求?
- python - 如何从两个不同的数据框创建列散点图?
- go - golang url.PathUnescape 不能在 %% 中工作
- c++ - 如何检查 O(N) 时间复杂度的多重集中是否有 2 个或多个具有相同值的元素?
- google-bigquery - 如何使用 BigQuery 查找字符串中子字符串的计数?
- bazel - 强制 Bazel 仅使用本地 java
- c# - Dockerized 应用程序找不到文件系统映像
- python - 是否可以更改 Seaborn 的集群图树状图中的线宽?