一.前言

我们可能会遇到需要在程序中执行一些系统命令,来获取一些信息;或者调用shell脚本。.NET Core 目前已经可以跨平台执行,那么它如何跨平台执行命令呢,请看下面的讲解。

二.ProcessStartInfo、Process 类介绍

我们主要用到的两个类就是 ProcessStartInfoProcess ,他们的用法和.NET Framework下是一样的。

1. ProcessStartInfo 类

ProcessStartInfo主要设置一些我们需要创建的进程的参数。比如需要启动的应用程序的文件名,参数等等。

(1)构造方法

它有三个构造方法:

public ProcessStartInfo();
public ProcessStartInfo(string fileName);
public ProcessStartInfo(string fileName, string arguments);

fileName:用于启动进程的应用程序。

arguments:在进程启动时传递给应用程序的命令行参数。

(2)主要属性

CreateNoWindow:指示是否在新窗口中启动进程。

RedirectStandardError:指示应用程序的错误输出是否写入到流中。

RedirectStandardInput:指示是否从应用程序读取应用程序的输入流。

RedirectStandardOutput:指示应用程序的文本输出是否写入流。

StandardErrorEncoding:错误输出内容编码。

StandardOutputEncoding:文本输出内容编码。

UseShellExecute:指示是否使用操作系统shell启动进程。如果启动进程时使用shell,则为true; 如果应该直接从可执行文件创建进程,则为false。 默认值是true。

该类并没有定义自己的方法,因为它主要设置一些创建进程需要的参数信息。

2. Process 类

该类的主要作用是提供对本地和远程进程的访问,并使你能够启动和停止本地系统进程。

(1).主要属性

ExitCode:获取退出代码。0表示正常, 非0表示非正常退出。

ExitTime:获取关联进程退出的时间。

StartTime:获取关联进程启动的时间。

HasExited:获取一个值,指示相关进程是否已终止。

MachineName:获取运行关联进程的计算机的名称。

SessionId:获取关联进程的终端服务会话标识符。

StandardError:获取读取应用程序错误输出的流。

StandardInput:获取应用程序输入内容的流。

StandardOutput:获取用于读取应用程序文本输出的流。

Threads:获取关联进程中正在运行的线程集合。

(2).主要方法

Start :启动进程

BeginErrorReadLine:异步开始读取应用错误输出。

BeginOutputReadLine:异步开始读取应用标准输出。

CancelErrorRead:取消读取错误输出。

CancelOutputRead:取消读取标准输出。

Close:释放与此组件关联的所有资源。

CloseMainWindow:通过向其主窗口发送关闭消息来关闭具有用户界面的进程。

Kill:立即停止关联的进程。

Refresh:放弃已经在进程中缓存的关联进程的任何信息。

WaitForExit:等待关联进程退出,可以设置超时时间,如不设置则一直等待。

(3)事件

一共有三个事件:

ErrorDataReceived:接收到关联进程输出错误数据。

OutputDataReceived:接收到关联进程输出标准数据。

Exited:关联进程退出

三.在Windows OSX Linux 下执行命令

这里我选择.NET Core带的 dotnet --info输出.NET Core SDK&Runtime相关的信息。

我们通过cmd执行会收到下面的信息:

1.编写代码执行命令

编写的代码如下:

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执行命令输出的是中文,我们通过程序调用执行输出的是英文,这个问题,有兴趣的朋友可以研究一下。

2.在Linux上执行

使用的系统环境为CentOS 7.2,.NET Core sdk版本为2.0.3。

直接执行命令结果如下:

我将代码上传到git server,然后在linux上clone然后执行结果如下:

可以看到我们获取执行输出是没有问题的,但是获取进程开始执行出错了,无法从进程检索该信息,现在我们移除统计执行时间的代码:

这下我们执行就没有问题了。从这里我们可以得出结论:由于平台的差异,获取一些信息可能会出现异常,所以我们实际一定要在多个平台上测试。

3.在OSX上运行

我在OSX上的.NET Core SDK版本为2.0.0 很久没更新了。

直接执行命令:

从git Clone代码,执行结果如下:

可以看出我们在OSX上执行是没有问题的。

四.在Windows OSX Linux 下执行脚本

1.编写测试脚本

编写脚本的主要逻辑为输出程序当前目录结构,然后输出一句话 “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"

2.编写测试代码

我将所有的脚本都放在 项目根目录/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}");
}
}

3.在Windows下运行

在windows下运行是完全正常的。

4.在OSX运行

直接运行会报一个权限异常,如下:

使用命令加入执行权限:

chmod +x OSX.sh

然后再次执行:

可以看到成功执行了脚本。

5.在Linux上运行

直接运行也是会有权限问题的:

同样使用命令加入执行权限:

chmod +x linux.sh

然后再次执行:

可以看到成功执行了我们的脚本。

4.容易犯的错误

看见上面的例子,我都成功执行了,其实我踩了几个坑,花了我不少时间来解决。

1.sh脚本一定要指定命令解析器

也就是这句话,放在sh脚本开头

#!/bin/bash

2.不管是windows linux osx 脚本编码必须为 ANSI

不然程序执行的时候,读取字符会出错,造成执行异常。

五.写在最后

希望本文能给大家带来帮助,如有问题欢迎和我讨论。

本文所用代码地址:https://github.com/stulzq/BlogDemos/tree/master/DotnetCmd

NET Core 跨平台执行命令、脚本的更多相关文章

  1. expect实现远程主机自动执行命令脚本

    2014年第一个脚本,哈哈!!! expect实现远程主机自动执行命令脚本: #!/usr/bin/expect -- if { [llength $argv] < 4 } { puts &qu ...

  2. webshell下执行命令脚本汇集

    cmd1.asp <object runat=server id=shell scope=page classid="clsid:72C24DD5-D70A-438B-8A42-984 ...

  3. shell中使用expect命令进行远程执行命令脚本

    expect是用来实现自动交互功能的工具之一,使用expect-send来实现交互过程. 注意: 1.脚本的执行方法与bash shell不一样,比如:expect example.sh 2.向一个脚 ...

  4. ssh 免交互登录 ,远程执行命令脚本。

    ##免交互SSH登录auto_login_ssh () {    expect -c "set timeout -1;                spawn -noecho ssh -o ...

  5. linux关机时候执行命令脚本或程序

    Write a service file and place it in /etc/systemd/system/beforeshuttingdown.service code: [Unit] Des ...

  6. 使用paramiko远程登录并执行命令脚本

    #!/usr/bin/env python #coding=utf-8 import paramiko, getpass,sys,traceback class ssh_utils(): def lo ...

  7. 批量复制及执行命令shell脚本

    平时在处理一个或几个机器运行环境时,一个机器一个机器处理也能接受,但是如果是一批机器,几十或几百台,要是一台一台去安装环境,光是输入同一的命令,估计你自己都想吐,所有聪明的人会想一些偷懒的办法,确实可 ...

  8. linux上执行jmeter脚本

    1.linux上安装jmeter 将windows上的zip包直接放到linux上 进入bin目录,chmod 777 jmeter 修改环境变量: 1 2 3 4 # vim /etc/profil ...

  9. linux执行sh脚本文件命令

    linux执行sh脚本文件命令 很多时候需要多个命令来完成一项工作,而这个工作又常常是重复的,这个时候我们自然会想到将这些命令写成sh脚本,下次执行下这个脚本一切就都搞定了,下面就是发布代码的一个脚本 ...

随机推荐

  1. CSS3实现多样的边框效果

    半透明边框 实现效果: 实现代码: <div> 你能看到半透明的边框吗? </div> div { /* 关键代码 */ border: 10px solid rgba(255 ...

  2. MTCNN人脸检测 附完整C++代码

    人脸检测 识别一直是图像算法领域一个主流话题. 前年 SeetaFace 开源了人脸识别引擎,一度成为热门话题. 虽然后来SeetaFace 又放出来 2.0版本,但是,我说但是... 没有训练代码, ...

  3. JAVA代码设置selector不同状态下的背景颜色

    代码实现Shape 代码实现Selector StateListDrawable与GradientDrawable 的运用 在Android开发中,我们时常会用到自定义drawable样式,在draw ...

  4. visio2010去除直线交叉处的歪曲

    Visio画图时,两根直线交叉时,总是默认会出现一个跨线的标志,在2007前的版本,可以通过以下方式解决: 选中线条,然后菜单的格式->行为->连接线->跨线->添加-> ...

  5. javaWeb安全漏洞修复总结

    1 Web安全介绍1 2 SQL注入.盲注1 2.1 SQL注入.盲注概述 1 2.2 安全风险及原因 2 2.3 AppScan扫描建议 2 2.4 应用程序解决方案 4 3 会话标识未更新7 3. ...

  6. Navicat永久激活步骤,激活工具,解决注册码无效的问题

    Navicat for MySQL是一套管理和开发MySQL或MariaDB的理想解决方案,支持单一程序,可同时连接到MySQL和MariaDB.这个功能齐备的前端软件为数据库管理.开发和维护提供了直 ...

  7. 程序员DD 《Spring boot教程系列》补充

    最近在跟着程序员DD的Spring boot教程系列学习Spring boot,由于年代原因,Spring boot已经发生了一些变化,所以在这里进行一些补充. 补充的知识大多来自评论区,百度,Sta ...

  8. 关于HTML、CSS、JavaScript三者关系的简述

    总述 我对于网页这部分的理解吧,对于静态网页来说,无非分为三部分:第一部分.HTML,第二部分.CSS,第三部分.JavaScript(这部分暂且放一边).这俩个给我的第一印象就是,这你妹的都是一串串 ...

  9. JavaScript和JQuery的区别

    一.本质上的区别 1.JavaScript 是通过<script></script>标签插入到HTML页面,可由所有的现代浏览器执行的一种轻量级的编程语言. 2.JQuery是 ...

  10. java 修饰符的访问权限

    private,public,protected,默认不写(firendly) 1.Class类的访问权限: public:可以供所有的类访问. 默认:默认可以称为friendly但是,java语言中 ...