咱们可能会遇到须要在程序中执行一些系统命令,来获取一些信息;或者调用shell脚本。.NET Core 目前已经能够跨平台执行,那么它如何跨平台执行命令呢,请看下面的讲解。linux
咱们主要用到的两个类就是 ProcessStartInfo
和 Process
,他们的用法和.NET Framework下是同样的。git
ProcessStartInfo
主要设置一些咱们须要建立的进程的参数。好比须要启动的应用程序的文件名,参数等等。github
它有三个构造方法:shell
public ProcessStartInfo(); public ProcessStartInfo(string fileName); public ProcessStartInfo(string fileName, string arguments);
fileName
:用于启动进程的应用程序。windows
arguments
:在进程启动时传递给应用程序的命令行参数。缓存
CreateNoWindow
:指示是否在新窗口中启动进程。bash
RedirectStandardError
:指示应用程序的错误输出是否写入到流中。异步
RedirectStandardInput
:指示是否从应用程序读取应用程序的输入流。测试
RedirectStandardOutput
:指示应用程序的文本输出是否写入流。编码
StandardErrorEncoding
:错误输出内容编码。
StandardOutputEncoding
:文本输出内容编码。
UseShellExecute
:指示是否使用操做系统shell启动进程。若是启动进程时使用shell,则为true; 若是应该直接从可执行文件建立进程,则为false。 默认值是true。
该类并无定义本身的方法,由于它主要设置一些建立进程须要的参数信息。
该类的主要做用是提供对本地和远程进程的访问,并使你可以启动和中止本地系统进程。
ExitCode
:获取退出代码。0表示正常, 非0表示非正常退出。
ExitTime
:获取关联进程退出的时间。
StartTime
:获取关联进程启动的时间。
HasExited
:获取一个值,指示相关进程是否已终止。
MachineName
:获取运行关联进程的计算机的名称。
SessionId
:获取关联进程的终端服务会话标识符。
StandardError
:获取读取应用程序错误输出的流。
StandardInput
:获取应用程序输入内容的流。
StandardOutput
:获取用于读取应用程序文本输出的流。
Threads
:获取关联进程中正在运行的线程集合。
Start
:启动进程
BeginErrorReadLine
:异步开始读取应用错误输出。
BeginOutputReadLine
:异步开始读取应用标准输出。
CancelErrorRead
:取消读取错误输出。
CancelOutputRead
:取消读取标准输出。
Close
:释放与此组件关联的全部资源。
CloseMainWindow
:经过向其主窗口发送关闭消息来关闭具备用户界面的进程。
Kill
:当即中止关联的进程。
Refresh
:放弃已经在进程中缓存的关联进程的任何信息。
WaitForExit
:等待关联进程退出,能够设置超时时间,如不设置则一直等待。
一共有三个事件:
ErrorDataReceived
:接收到关联进程输出错误数据。
OutputDataReceived
:接收到关联进程输出标准数据。
Exited
:关联进程退出
这里我选择.NET Core带的 dotnet --info
输出.NET Core SDK&Runtime相关的信息。
咱们经过cmd执行会收到下面的信息:
编写的代码以下:
static void Main() { //建立一个ProcessStartInfo对象 使用系统shell 指定命令和参数 设置标准输出 var psi = new ProcessStartInfo("dotnet", "--info") {RedirectStandardOutput = true}; //启动 var proc=Process.Start(psi); if (proc == null) { Console.WriteLine("Can not exec."); } else { Console.WriteLine("-------------Start read standard output--------------"); //开始读取 using (var sr = proc.StandardOutput) { while (!sr.EndOfStream) { Console.WriteLine(sr.ReadLine()); } if (!proc.HasExited) { proc.Kill(); } } Console.WriteLine("---------------Read end------------------"); Console.WriteLine($"Total execute time :{(proc.ExitTime-proc.StartTime).TotalMilliseconds} ms"); Console.WriteLine($"Exited Code : {proc.ExitCode}"); } }
执行结果以下:
从执行结果能够看出,咱们经过编写的程序来执行dotnet --info
命令获取的结果几乎同样,只有第一行的提示,咱们经过cmd执行命令输出的是中文,咱们经过程序调用执行输出的是英文,这个问题,有兴趣的朋友能够研究一下。
使用的系统环境为CentOS 7.2,.NET Core sdk版本为2.0.3。
直接执行命令结果以下:
我将代码上传到git server,而后在linux上clone而后执行结果以下:
能够看到咱们获取执行输出是没有问题的,可是获取进程开始执行出错了,没法从进程检索该信息,如今咱们移除统计执行时间的代码:
这下咱们执行就没有问题了。从这里咱们能够得出结论:因为平台的差别,获取一些信息可能会出现异常,因此咱们实际必定要在多个平台上测试。
我在OSX上的.NET Core SDK版本为2.0.0 好久没更新了。
直接执行命令:
从git Clone代码,执行结果以下:
能够看出咱们在OSX上执行是没有问题的。
编写脚本的主要逻辑为输出程序当前目录结构,而后输出一句话 “dotnet in 操做系统类型”
Windows: win.bat
@echo off dir echo "dotnet in Windows"
Linux: linux.sh
#!/bin/bash ls echo "dotnet in Linux"
OSX: OSX.sh
#!/bin/bash ls echo "dotnet in OSX"
我将全部的脚本都放在 项目根目录/shell 文件夹下。
由于咱们须要根据不一样的操做类型,选择不一样的脚原本进行执行,因此咱们须要在代码里面判断一下操做系统类型。咱们能够经过 RuntimeInformation.IsOSPlatform
来判断。
static void Main() { string fileName="shell/"; //根据系统使用不一样的shell文件 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { fileName += "win.bat"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { fileName += "linux.sh"; } else { fileName += "OSX.sh"; } //建立一个ProcessStartInfo对象 使用系统shell 指定命令和参数 设置标准输出 var psi = new ProcessStartInfo(fileName) { RedirectStandardOutput = true }; //启动 var proc = Process.Start(psi); if (proc == null) { Console.WriteLine("Can not exec."); } else { Console.WriteLine("-------------Start read standard output--------------"); //开始读取 using (var sr = proc.StandardOutput) { while (!sr.EndOfStream) { Console.WriteLine(sr.ReadLine()); } if (!proc.HasExited) { proc.Kill(); } } Console.WriteLine("---------------Read end------------------"); Console.WriteLine($"Exited Code : {proc.ExitCode}"); } }
在windows下运行是彻底正常的。
直接运行会报一个权限异常,以下:
使用命令加入执行权限:
chmod +x OSX.sh
而后再次执行:
能够看到成功执行了脚本。
直接运行也是会有权限问题的:
一样使用命令加入执行权限:
chmod +x linux.sh
而后再次执行:
能够看到成功执行了咱们的脚本。
看见上面的例子,我都成功执行了,其实我踩了几个坑,花了我很多时间来解决。
也就是这句话,放在sh脚本开头
#!/bin/bash
否则程序执行的时候,读取字符会出错,形成执行异常。
但愿本文能给你们带来帮助,若有问题欢迎和我讨论。
本文所用代码地址:https://github.com/stulzq/BlogDemos/tree/master/DotnetCmd