网上一直有经久不衰的语言之争。有的说java比C#强,有的说c++比c好。有的说php是最好的语言等等。其实语言只是个工具,每个语言的适合场景有差别,也说不上谁好谁坏。
记得14年的时候我刚用M的时候就吐槽这什么语言,开发效率比SQL低多了,到现在的很依赖M提高执行效率。所以说语言还得看重适合,比如C就不太适合那些天天变需求的业务系统。
为了简化系统跨平台后的运维操作,在运维方面还是下了很大功夫的。最终给运维压缩到一个imedicallis命令上。所以平常回答问题说的imedicallis 4是指在shell运行imedicallis命令,选4回车。
那么imedicallis命令的背后是什么?
这里就得说一下linux下的命令概念了。我刚开始学习linux时候对命令也决定很神奇,感觉离开发很遥远。随着学习深入之后,我归纳linux命令就是“控制台程序”,我大学时候学C++时候瞧不上眼的控制台程序。控制台里面有标准输入、标准输出、标准错误。在运行环境里标准输入这些是什么或者重定向到什么就输入输出到什么上了。所以linux的命令就是shell调你实现的控制台把输入通过标准输入给到你控制台的main参数。你控制台按参数执行,程序里面的标准输出再重定向到shell里。所以如果你是个程序员,那么像linux命令echo,tree,touch,rm,mkdir等命令都可以自己写控制台实现。把编译的程序投入usr/bin下就能直接输入编译文件名字当命令了。不在命令那几个搜索目录下的话就得敲全路径了。
比如实现一个tree命令,shell的参数就是通过标准输入传递给main的参数了,而标准输出又直接输出到shell了。这就是shell调用c语言程序的功能
#include <iostream>
#include <string>
#include <cstring>
#include <regex>
//引用命名空间
using namespace std;
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#else
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#endif
/// <summary>
/// 用数列出目录
/// </summary>
/// <param name="dir">目录</param>
/// <param name="level">层级</param>
void TreeDir(const string dir, int level);
/// <summary>
/// 得到当前系统目录对应linux的pwd
/// </summary>
/// <returns>当前系统工作目录</returns>
string GetSystemCurrentPath()
{
char buf[1024] = "";
string path = string();
#ifdef _WIN32
getcwd(buf, sizeof(buf));
regex reg("\\\\");
path = regex_replace(buf, reg, "/");
#else
getcwd(buf, sizeof(buf));
path = string(buf);
#endif
return path;
}
/// <summary>
/// 主方法
/// </summary>
/// <param name="argc">参数个数</param>
/// <param name="argv">参数数组</param>
/// <returns></returns>
int main(int argc, char* argv[])
{
string dir;
//有参数就按参数传
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
dir = argv[i];
TreeDir(dir, 0);
}
}
else
{
//否则当前路径
dir = GetSystemCurrentPath();
cout << "当前工作路径:" << dir << endl;
TreeDir(dir, 0);
}
return 0;
}
#ifdef _WIN32
/// <summary>
/// 用数列出目录的东西
/// </summary>
/// <param name="dir">目录</param>
/// <param name="level">层级</param>
void TreeDir(const string dir, int level)
{
string dirNew = dir;
// 在目录后面加上"\\*.*"进行第一次搜索
dirNew += "\\*.*";
//句柄
intptr_t handle;
//文件结构体数据
_finddata_t findData;
//查询第一个到结构体
handle = _findfirst(dirNew.c_str(), &findData);
if (level == 0)
{
cout << "." << endl;
}
if (handle == -1)
{
cout << dir << "下没找到东西!" << endl;
return;
}
//遍历
do
{
//是子目录
if (findData.attrib & _A_SUBDIR)
{
if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
{
continue;
}
string levelStr = "|";
if (level > 0)
{
for (int i = 0; i < level; i++)
{
levelStr += " ";
}
levelStr += "└── ";
}
cout << levelStr << "\033[34m" << findData.name << "\033[0m" << endl;
dirNew = dir + "\\" + findData.name;
// 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
TreeDir(dirNew, ++level);
}
else
{
string levelStr = "|";
if (level > 0)
{
for (int i = 0; i < level; i++)
{
levelStr += " ";
}
levelStr += "└── ";
}
cout << levelStr << findData.name << "\t\033[31m " << findData.size << " bytes\033[0m \033[33m" << (findData.size * 1.0 / 1048576) << "兆\033[0m" << endl;
}
} while (_findnext(handle, &findData) == 0);
// 关闭搜索句柄
_findclose(handle);
}
#else
/// <summary>
/// 判断路径是否是文件夹
/// </summary>
/// <param name="path">路径</param>
/// <returns>返回值</returns>
int PathIsDir(const char* path) {
struct stat st;
stat(path, &st);
if (S_ISDIR(st.st_mode)) {
return 1;
}
else {
return 0;
}
}
/// <summary>
/// 得到文件的大小
/// </summary>
/// <param name="fname">文件路径</param>
/// <returns></returns>
int GetFileSize(const char* fname)
{
struct stat statbuf;
if (stat(fname, &statbuf) == 0)
{
return statbuf.st_size;
}
return -1;
}
/// <summary>
/// 用数列出目录的东西
/// </summary>
/// <param name="dir">目录</param>
/// <param name="level">层级</param>
void TreeDir(const string dir, int level)
{
DIR* dirptr = NULL;
struct dirent* entry;
string dirNew;
if (level == 0)
{
cout << "." << endl;
}
if ((dirptr = opendir(dir.c_str())) == NULL)
{
cout << dir << "下没找到东西!" << endl;
return;
}
else
{
while (entry = readdir(dirptr))
{
dirNew = dir + "/" + entry->d_name;
//是子目录
if (PathIsDir(dirNew.c_str()) == 1)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
string levelStr = "|";
if (level > 0)
{
for (int i = 0; i < level; i++)
{
levelStr += " ";
}
levelStr += "└── ";
}
cout << levelStr << "\033[34m" << entry->d_name << "\033[0m" << endl;
// 在目录后面加上"//"和搜索到的目录名进行下一次搜索
TreeDir(dirNew, ++level);
}
else
{
string levelStr = "|";
if (level > 0)
{
for (int i = 0; i < level; i++)
{
levelStr += " ";
}
levelStr += "└── ";
}
int fileSize = GetFileSize(dirNew.c_str());
cout << levelStr << entry->d_name <<" "<< fileSize << " bytes\033[0m \033[33m " << (fileSize * 1.0 / 1048576) << "兆\033[0m" << endl;
}
}
closedir(dirptr);
}
}
#endif
所以imedicallis命令就是一个c++控制台程序,只是放在了usr/bin下了,所以直接敲imedicallis可以呼出。这里为什么要用c/c++实现而不用C#实现是因为C#需要运行时,运行时候还得用dotnet命令驱动实现的dll,这样就会让命令又长又难记。用bash实现一样得用bash名字跟文件路径体验不好。c/c++没运行时依赖,所以适合实现命令。
实现很简单,就是去驱动shell,刚才是shell驱动控制台,现在是c怎么驱动bash
#include<cstdlib>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
//定义数组大小
#define NUM 900
//执行方法
extern void Invoke(string cmd);
#ifdef WIN32
/// <summary>
/// 执行命令
/// </summary>
/// <param name="cmd"></param>
void Invoke(string cmd)
{
cout << "仅支持linux驱动检验运维命令:" << cmd << endl;
}
#else
#include<stdlib.h>
/// <summary>
/// 执行命令
/// </summary>
/// <param name="cmd"></param>
void Invoke(string cmd)
{
char cmdArr[NUM];
cmd.copy(cmdArr, cmd.length(), 0);
system(cmd.c_str());
return;
char line[NUM];
FILE* fp;
//系统调用
const char* sysCommand = cmd.data();
if ((fp = popen(sysCommand, "r")) == NULL)
{
cout << "错误" << endl;
return;
}
//输出
while (fgets(line, sizeof(line) - 1, fp) != NULL)
{
cout << line;
}
pclose(fp);
}
#endif
/// <summary>
/// mian方法
/// </summary>
/// <returns></returns>
int main() {
//执行bash脚本
string cmdStr = "bash /p1/p2/p3/imedicallis/tool/lis.sh";
cout << "欢迎使用imedicallis的linux命令呼出入口,通过imedicallis命令引导bash脚本" << endl;
cout << "执行命令:" << cmdStr<<endl;
//执行命令
Invoke(cmdStr);
return 0;
}
通过上面就得到一个c编译的控制台,投入usr/bin下即是imedicallis命令。为啥不把功能也用c实现了呢?而是驱动bash呢?这里就得说到语言适用性了,因为运维命令是业务性质的,要方便调整。所以写在c里面不方便,每次还得编译替换。所以引入bash的脚本便捷性来做运维命令的主体。shell作为胶水性质的脚本,融合大家是他的强项。运行imedicallis之后c程序把逻辑引入lis.sh脚本。
这个脚本里就在执行一个死循环不停输出菜单目录和判断输入选择,然后按选择执行shell命令。
说到这里似乎已经完事了。实际并没有完事,shell作为运维脚本是方便,也要linux文本三剑客awk、grep、sed。说实在的我学的时候看着文本三剑客的正则,写的复杂性头大,为没学文本三剑客。所以我有shell读写配置文件就是难搞。所以就得发挥shell胶水特长了,用shell驱动dotnet命令调用C#程序实现文本读写,为啥这里不调c而调C#了?因为我c不强啊,而且就算能c实现用C#写的也简单些。shell调c的控制台和C#的控制台是一样的额,都是符合标准输入输出的。
下面就算shell驱动dotnet实现的控制台程序的例子
#编译LIS.Model进行比对
elif [ ${check} -eq 18 ];then
echo "开始编译/p1/p2/p3/imedicallis/LIS.Model/LIS.ModelCheck.csproj的代码用来实体比对"
dotnet build -v n /p1/p2/p3/imedicallis/LIS.Model/LIS.ModelCheck.csproj
echo "编译完成,进行实体比对"
dotnet /p1/p2/p3/imedicallis/tool/lismodelcompare/lismodelcompare.dll "/p1/p2/p3/imedicallis/LIS.Model.dll" "/p1/p2/p3/imedicallis/LIS.Model/bin/LIS.ModelCheck.dll"
#编译LIS.Model
elif [ ${check} -eq 8 ];then
echo "开始编译/p1/p2/p3/imedicallis/LIS.Model/LIS.Model.csproj的代码"
dotnet build -v n /p1/p2/p3/imedicallis/LIS.Model/LIS.Model.csproj
echo "编译完成,准备重启网站"
echo "停止检验网站"
sudo systemctl stop imedicallis.service
systemctl daemon-reload
echo "启动检验网站"
sudo systemctl start imedicallis.service
echo "检验网站状态"
sudo systemctl status imedicallis.service
C#控制台的实现,用标准输入输出即可
using LIS.DAL.ORM.CustomAttributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
namespace lismodelcompare
{
class Program
{
/// <summary>
/// 存对比信息
/// </summary>
private static List<ComPareDto> list = new List<ComPareDto>();
/// <summary>
/// 对比实体主逻辑
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//没参数提示
if (args == null || args.Length < 2)
{
Console.WriteLine("没有传入两个路径参数!");
return;
}
string pathOld = args[0];
string pathNew = args[1];
if (pathOld != "" && pathNew != "")
{
if (!File.Exists(pathOld))
{
Console.WriteLine(pathOld + "不存在!");
return;
}
if (!File.Exists(pathNew))
{
Console.WriteLine(pathNew + "不存在!");
return;
}
//清除之前数据
list.Clear();
//加载程序集
Assembly assemblyOne = null;
Assembly assemblyTow = null;
AssemblyLoadContext assemblyLoadContextOne = new AssemblyLoadContext("one", true);
AssemblyLoadContext assemblyLoadContextTow = new AssemblyLoadContext("tow", true);
//以只读方式读dll
using (FileStream fs = new FileStream(pathOld, FileMode.Open, FileAccess.Read))
{
assemblyOne = assemblyLoadContextOne.LoadFromStream(fs);
}
//以只读方式读dll
using (FileStream fs = new FileStream(pathNew, FileMode.Open, FileAccess.Read))
{
assemblyTow = assemblyLoadContextOne.LoadFromStream(fs);
}
//获得动态库1的所有类型数组
Type[] typeOnes = assemblyOne.GetTypes();
//循环比较类型
foreach (var v in typeOnes)
{
Type typeTow = assemblyTow.GetType(v.FullName);
//动态库1有的动态库2的没有
if (typeTow == null)
{
ComPareType(v, null);
}
//比较属性,两个都有的
else
{
ComPareType(v, typeTow);
}
}
//获得动态库2的所有类型数组
Type[] typeTows = assemblyTow.GetTypes();
//循环比较类型
foreach (var v in typeTows)
{
Type typeOne = assemblyOne.GetType(v.FullName);
//动态库2有的,动态库1没有的美学
if (typeOne == null)
{
ComPareType(null, v);
}
}
//没有差异
if (list.Count == 0)
{
Console.WriteLine("比对实体结束!");
Console.WriteLine("你比较的两个实体没有任何差异!");
}
else
{
foreach (ComPareDto one in list)
{
Console.WriteLine("----------------------------------------------------------------------------------------------------");
Console.WriteLine(one.Name + "存在差异");
Console.WriteLine("老代码如下:");
Console.WriteLine("*****************************************************************");
Console.WriteLine(one.OneStr);
Console.WriteLine("*****************************************************************");
Console.WriteLine("新代码如下:");
Console.WriteLine("*****************************************************************");
Console.WriteLine(one.TowStr);
Console.WriteLine("*****************************************************************");
Console.WriteLine("----------------------------------------------------------------------------------------------------");
Console.WriteLine(" ");
Console.WriteLine(" ");
Console.WriteLine(" ");
}
Console.WriteLine("比对实体结束!");
Console.WriteLine("有:" + list.Count + "个表存在差异");
Console.WriteLine("数据太多可以右键开启Shell日志比对!");
}
}
}
/// <summary>
/// 比较类型
/// </summary>
/// <param name="one">类型1</param>
/// <param name="tow">类型2</param>
private static void ComPareType(Type one, Type tow)
{
ComPareDto dto = new ComPareDto();
//类型1不为空,写类型代码
if (one != null)
{
dto.Name = one.FullName;
dto.OneStr = GetTypeStr(one);
}
//类型2不为空,写类型代码
if (tow != null)
{
dto.Name = tow.FullName;
dto.TowStr = GetTypeStr(tow);
}
//不同的加入
if (dto.IsCom == false)
{
dto.OneStr = GetClassCodeByType(one, true);
dto.TowStr = GetClassCodeByType(tow, true);
list.Add(dto);
}
}
/// <summary>
/// 通过类型得到类代码
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
private static string GetClassCodeByType(Type v, bool noHead = false)
{
if (v == null)
{
return "";
}
//清空原来内容
StringBuilder sb = new StringBuilder();
string fullName = v.FullName;
string name = v.Name;
sb.AppendLine("using System;");
sb.AppendLine("using System.Data;");
sb.AppendLine("using LIS.DAL.ORM.CustomAttributes;");
sb.AppendLine("");
sb.AppendLine("namespace " + v.Namespace);
sb.AppendLine("{");
if (noHead == false)
{
sb.AppendLine(" ///<summary NoteObject=\"Class\">");
sb.AppendLine(" /// [功能描述:本代码由LIS内部代码生成工具生成,请不要手动修改,如要修改,请写修改变更记录] <para/>");
sb.AppendLine(" /// [创建者:LIS代码生成器] <para/>");
sb.AppendLine(" /// [创建时间:2014年12月26日] <para/>");
sb.AppendLine(" ///<说明>");
sb.AppendLine(" /// [说明:本代码由LIS内部代码生成工具生成,请不要手动修改]<para/>");
sb.AppendLine(" ///</说明>");
sb.AppendLine(" ///<修改记录>");
sb.AppendLine(" /// [修改时间:本次修改时间]<para/>");
sb.AppendLine(" /// [修改内容:本次修改内容]<para/>");
sb.AppendLine(" ///</修改记录>");
sb.AppendLine(" ///<修改记录>");
sb.AppendLine(" /// [修改时间:本次修改时间]<para/>");
sb.AppendLine(" /// [修改内容:本次修改内容]<para/>");
sb.AppendLine(" ///</修改记录>");
sb.AppendLine(" ///</summary>");
}
sb.AppendLine(" [Serializable]");
//获取所有类特性
var classAttrs = v.GetCustomAttributes(false);
string tableAtrr = "";
foreach (var classAttr in classAttrs)
{
//如果类属性是表属性类型
if (classAttr is TableAttribute)
{
//as转换类型
TableAttribute tableAttr = classAttr as TableAttribute;
string tableName = tableAttr.Name;
//得到表名
string tableRemark = tableAttr.Remark;
tableAtrr = " [Table(Name = \"" + tableName + "\", Remark = \"" + tableRemark + "\")]";
}
//如果类属性是唯一性属性类型
if (classAttr is UniqueAttribute)
{
//as转换类型
UniqueAttribute uniqueAttr = classAttr as UniqueAttribute;
string colNames = uniqueAttr.ColNames;
sb.AppendLine(" [Unique(ColNames = \"" + colNames + "\")]");
}
}
//表特性靠下
if (tableAtrr != "")
{
sb.AppendLine(tableAtrr);
}
sb.AppendLine(" public class " + name + " : LIS.Core.Dto.BaseDto");
sb.AppendLine(" {");
//开始属性代码
//得到属性
PropertyInfo[] properties = v.GetProperties();
//遍历生成属性代码
foreach (var p in properties)
{
sb.AppendLine(" /// <summary>");
sb.AppendLine(" ///" + p.Name);
sb.AppendLine(" /// </summary>");
//返回所有自定义特性
object[] propertyAttrs = p.GetCustomAttributes(false);
//遍历所有自定义特性
for (int i = 0; i < propertyAttrs.Length; i++)
{
//获取当前的自定义特性
object propertyAttr = propertyAttrs[i];
//如果是外键特性
if (propertyAttr is FrekeyAttribute)
{
//强制转换成外键特性
FrekeyAttribute fkAttr = propertyAttr as FrekeyAttribute;
string associaField1 = "";
string associaField2 = "";
if (fkAttr.AssociaField1 != null && fkAttr.AssociaField1 != "")
{
associaField1 = ", AssociaField1 = \"" + fkAttr.AssociaField1 + "\"";
}
if (fkAttr.AssociaField2 != null && fkAttr.AssociaField2 != "")
{
associaField2 = ", AssociaField2 = \"" + fkAttr.AssociaField2 + "\"";
}
sb.AppendLine(" [Frekey(Name = \"" + fkAttr.Name + "\", RefColumnName = \"" + fkAttr.RefColumnName + "\", AssociaField = \"" + fkAttr.AssociaField + "\"" + associaField1 + associaField2 + ")]");
}
//如果是主键特性
if (propertyAttr is IdAttribute)
{
//强制转换成
IdAttribute idAttr = propertyAttr as IdAttribute;
sb.AppendLine(" [Id(Name = \"" + idAttr.Name + "\", Strategy = GenerationType.INDENTITY)]");
}
//如果是非空特性
if (propertyAttr is NotNullAttribute)
{
//强制转换成
NotNullAttribute notNullAttr = propertyAttr as NotNullAttribute;
sb.AppendLine(" [NotNull]");
}
//如果是长度特性
if (propertyAttr is LengthAttribute)
{
//强制转换成
LengthAttribute lengthAttr = propertyAttr as LengthAttribute;
sb.AppendLine(" [Length(MaxLen = " + lengthAttr.MaxLen + ")]");
}
}
string typeStr = "";
if (p.PropertyType == typeof(int))
{
typeStr = "int";
}
else if (p.PropertyType == typeof(int?))
{
typeStr = "int?";
}
else if (p.PropertyType == typeof(string))
{
typeStr = "string";
}
else if (p.PropertyType == typeof(float))
{
typeStr = "float";
}
else if (p.PropertyType == typeof(float?))
{
typeStr = "float?";
}
else if (p.PropertyType == typeof(bool))
{
typeStr = "bool";
}
else if (p.PropertyType == typeof(bool?))
{
typeStr = "bool?";
}
else if (p.PropertyType == typeof(double))
{
typeStr = "double";
}
else if (p.PropertyType == typeof(double?))
{
typeStr = "double?";
}
else if (p.PropertyType == typeof(decimal))
{
typeStr = "decimal";
}
else if (p.PropertyType == typeof(decimal?))
{
typeStr = "decimal?";
}
else if (p.PropertyType == typeof(Byte[]))
{
typeStr = "Byte[]";
}
else
{
typeStr = p.PropertyType.Name;
}
sb.AppendLine(" public " + typeStr + " " + p.Name + "");
sb.AppendLine(" {");
sb.AppendLine(" get;");
sb.AppendLine(" set;");
sb.AppendLine(" }");
sb.AppendLine("");
}
//类结尾
sb.AppendLine(" }");
sb.AppendLine("}");
return sb.ToString();
}
/// <summary>
/// 获得类型串
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static string GetTypeStr(Type type)
{
StringBuilder sb = new StringBuilder();
if (type.FullName == type.Name)
{
return "";
}
sb.AppendLine("namespace " + type.FullName.Remove(type.FullName.Length - type.Name.Length - 1));
sb.AppendLine("{");
sb.AppendLine(" public class " + type.Name);
sb.AppendLine(" {");
//得到所有属性
PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
if (props != null && props.Length > 0)
{
foreach (var p in props)
{
string typeStr = "";
if (p.PropertyType == typeof(int))
{
typeStr = "int";
}
else if (p.PropertyType == typeof(int?))
{
typeStr = "int?";
}
else if (p.PropertyType == typeof(string))
{
typeStr = "string";
}
else if (p.PropertyType == typeof(float))
{
typeStr = "float";
}
else if (p.PropertyType == typeof(float?))
{
typeStr = "float?";
}
else if (p.PropertyType == typeof(bool))
{
typeStr = "bool";
}
else if (p.PropertyType == typeof(bool?))
{
typeStr = "bool?";
}
else if (p.PropertyType == typeof(double))
{
typeStr = "double";
}
else if (p.PropertyType == typeof(double?))
{
typeStr = "double?";
}
else if (p.PropertyType == typeof(decimal))
{
typeStr = "decimal";
}
else if (p.PropertyType == typeof(decimal?))
{
typeStr = "decimal?";
}
else if (p.PropertyType == typeof(Byte[]))
{
typeStr = "Byte[]";
}
else
{
typeStr = p.PropertyType.ToString();
}
sb.AppendLine(" public " + typeStr + " " + p.Name);
sb.AppendLine(" {");
sb.AppendLine(" set;");
sb.AppendLine(" get;");
sb.AppendLine(" }");
sb.AppendLine("");
}
}
sb.AppendLine(" }");
sb.AppendLine("}");
return sb.ToString();
}
/// <summary>
/// 比较结果实体
/// </summary>
private class ComPareDto
{
/// <summary>
/// 实体1串
/// </summary>
private string oneStr;
/// <summary>
/// 实体2串
/// </summary>
private string towStr;
/// <summary>
/// 是否一样
/// </summary>
public bool IsCom
{
get;
set;
}
/// <summary>
/// 类名
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// 类型1代码
/// </summary>
public string OneStr
{
get
{
return oneStr;
}
set
{
oneStr = value;
if (oneStr == towStr)
{
IsCom = true;
}
else
{
IsCom = false;
}
}
}
/// <summary>
/// 类型2代码
/// </summary>
public string TowStr
{
get
{
return towStr;
}
set
{
towStr = value;
if (oneStr == towStr)
{
IsCom = true;
}
else
{
IsCom = false;
}
}
}
}
}
}
通过上面就把shell不好处理的一些执行流引入C#了,借助C#的优势处理这部分。对C#有些得借助shell命令的也得驱动shell实现功能。
比如做自动更新时候的文件授权
/// <summary>
/// 授权
/// </summary>
/// <param name="path"></param>
private static void ChMod(string path)
{
if (!path.Contains("/"))
{
return;
}
var psi = new ProcessStartInfo("chmod", " -R 777 " + path)
{
RedirectStandardOutput = true,
RedirectStandardInput = true
};
Console.WriteLine("执行:" + "chmod -R 777 " + path + "命令");
//启动进程
Process proc = Process.Start(psi);
}
比如做自动编译
var cmmand = "dotnet";
//创建一个ProcessStartInfo对象 使用系统shell指定命令和参数 设置标准输出
var psi = new ProcessStartInfo(cmmand, "build -v n " + proBuildPath) { RedirectStandardOutput = true };
//启动
proc = Process.Start(psi);
if (proc == null)
{
LIS.Core.Util.LogUtils.WriteSecurityLog("编译:" + codepath + "无法运行命令!");
return "编译:" + codepath + "无法运行命令!";
}
else
{
StringBuilder retsb = new StringBuilder();
DateTime dtStart = DateTime.Now;
//读取标准输出
using (var sr = proc.StandardOutput)
{
while (!sr.EndOfStream)
{
retsb.Append(sr.ReadLine());
LIS.Core.Util.LogUtils.WriteSecurityLog(sr.ReadLine());
if((DateTime.Now- dtStart).TotalSeconds>60)
{
break;
}
}
//删除源文件
DeleteDirectory(proBuildPath);
}
//进程没结束就杀进程
if (!proc.HasExited)
{
proc.Kill(true);
}
if (proc.ExitCode == 0)
{
return "";
}
string retstr = retsb.ToString();
//摘要信息
int SummaryIndex = retstr.IndexOf("FAILED.Build");
string Summary = "";
if(SummaryIndex>0)
{
Summary = retstr.Substring(SummaryIndex);
}
if(Summary!="")
{
return "*************************错误摘要:"+Summary + "*************************错误详细信息:" + retstr;
}
return retstr;
}
}
catch (Exception ex)
{
//进程没结束就杀进程
if (proc != null && !proc.HasExited)
{
proc.Kill(true);
}
return ex.Message;
}
}
所以imedicallis命令的实现就是由c控制台引导。由bash控制主体,由C#实现费劲部分的集合体。有些功能在shell和C#执行穿插调用。用各语言擅长点和开发的擅长点结合。我也是奉行shell命令常用的就行了,实在实现费劲的就C#写程序实现,少学几个控制台工具而已。
还是linux提高快,没跨平台之前还是视野太窄了,怪不得一直有Java鄙视C#的传说,都跨平台了就看生态大小了,也不一定得跟互联网大厂的节奏,C#的优势是全能,开发web的同时开发桌面,串口等可以降低一些成本,基本都能干。