使用C#给Linux写Shell脚本(下篇)
<p> 在上篇的《使用C#给Linux写Shell脚本》结尾中,我们留下了一个关于C#如何调用BashShell的问题。在文章发布之后,我留意到有读者留言推荐使用“Pash”(一款类PowerShell的东西),在我下载并安装了该项目之后,尝试之下发现这仍然不是我们想要的。似乎C#还真的没有提供这种(输出重定向)功能,这也迫使我们采取了其他方式来实现。在本篇中,我们将提升“恫吓”等级并顺带把这个难题一并解决,各位看官请系好安全带。</p><p><img src="//images0.cnblogs.com/blog2015/499899/201505/032335171156419.gif"></p>
<p> 本篇中,我们将介绍:</p>
<p> (1)、C#直接调用BashShell所遭遇的问题</p>
<p> (2)、使用C的popen方式调用BashShell</p>
<p> (3)、通过调用C来间接的调用BashShell</p>
<hr>
<p> 一、C#直接调用BashShell所产生的问题</p>
<p> 使用C#调其他应用,毫无疑问最直接的方法就是“System.Diagnostics”中的Process.Start了。但当我们使用Process.Start时,却发现连最简单的命令都无法调用,更无从谈起调用并接受返回了。</p>
<p><img src="//images0.cnblogs.com/blog2015/499899/201505/032336335364505.png"></p>
<p> 上图为其中一种错误(当然还会有更多的问题出现,这里就不列举了)。</p>
<p> </p>
<p> 二、使用C的popen方式调用</p>
<p> 正由于Process.Start无法直接调用BashShell的命令,我们需要绕道而行。</p>
<p> 我们先看下C语言,C语言调用Shell的方式有多种,我们选择了popen函数的方式进行调用,先看一下以下的这个demo:</p>
<div class="cnblogs_code">
<pre>#include<stdio.h>
<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> main(){
FILE </span>*<span style="color: rgba(0, 0, 0, 1)">fp;
</span><span style="color: rgba(0, 0, 255, 1)">char</span> buffer[<span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">];
fp</span>=popen(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ls /home/le</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">r</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
fread(buffer,</span><span style="color: rgba(128, 0, 128, 1)">255</span>,<span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">,fp);
pclose(fp);
printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,buffer);
}</span></pre>
</div>
<p><img src="//images0.cnblogs.com/blog2015/499899/201505/032337488181806.png"></p>
<p> 通过poepn管道并完成输出重定向。</p>
<p> </p>
<p> 三、通过调用C来间接调用Shell</p>
<p> 既然C已经可以实现对BashShell的调用已经管道重定向,那我们则可以再通过C#调用C的方式,进而间接的完成对BashShell的调用。</p>
<p> 我们先对自己的C函数进行改造,改造后的代码如下(对具体操作有疑问的读者可参见《如何让C为C#提供函数》):</p>
<div class="cnblogs_code">
<pre>#include<stdio.h><span style="color: rgba(0, 0, 0, 1)">
#include</span><<span style="color: rgba(0, 0, 255, 1)">string</span>.h>
<span style="color: rgba(0, 0, 255, 1)">void</span>* ConvertToCStr(<span style="color: rgba(0, 0, 255, 1)">char</span>* input,<span style="color: rgba(0, 0, 255, 1)">char</span>* res,<span style="color: rgba(0, 0, 255, 1)">int</span> *<span style="color: rgba(0, 0, 0, 1)">length){
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> i;
</span><span style="color: rgba(0, 0, 255, 1)">for</span>(i=<span style="color: rgba(128, 0, 128, 1)">0</span>;i<*length;i++<span style="color: rgba(0, 0, 0, 1)">){
res</span>=*(input+<span style="color: rgba(128, 0, 128, 1)">2</span>*<span style="color: rgba(0, 0, 0, 1)">i);
}
res</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\0</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">void</span>* BashHelper(<span style="color: rgba(0, 0, 255, 1)">char</span>* cmdStr,<span style="color: rgba(0, 0, 255, 1)">int</span>* cmdLength,<span style="color: rgba(0, 0, 255, 1)">char</span>* output,<span style="color: rgba(0, 0, 255, 1)">int</span>*<span style="color: rgba(0, 0, 0, 1)"> length){
FILE</span>*<span style="color: rgba(0, 0, 0, 1)"> fp;
</span><span style="color: rgba(0, 0, 255, 1)">char</span> buffer[*<span style="color: rgba(0, 0, 0, 1)">length];
</span><span style="color: rgba(0, 0, 255, 1)">char</span> cmd[*cmdLength+<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">];
ConvertToCStr(cmdStr,cmd,cmdLength);
fp</span>=popen(cmd,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">r</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
fread(buffer,</span>*length,*<span style="color: rgba(0, 0, 0, 1)">length,fp);
pclose(fp);
strcat(output,buffer);
}</span></pre>
</div>
<p> 同样的我们也把C# Shell进行改造(没有Intellisense果然难写,我先在控制台写好再拷贝过来)</p>
<div class="cnblogs_code">
<pre>#!/bin/<span style="color: rgba(0, 0, 0, 1)">env csharp
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Diagnostics;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.IO;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Runtime.InteropServices;
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Clib
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">string</span> InvokeBash(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> cmdStr)
{
</span><span style="color: rgba(0, 0, 255, 1)">char</span>[] output = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[<span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 0, 255, 1)">unsafe</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">fixed</span> (<span style="color: rgba(0, 0, 255, 1)">char</span>* c =<span style="color: rgba(0, 0, 0, 1)"> cmdStr)
</span><span style="color: rgba(0, 0, 255, 1)">fixed</span> (<span style="color: rgba(0, 0, 255, 1)">char</span>* op =<span style="color: rgba(0, 0, 0, 1)"> output)
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span> cmdLenth =<span style="color: rgba(0, 0, 0, 1)"> cmdStr.Length;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> outputLength =<span style="color: rgba(0, 0, 0, 1)"> output.Length;
Clib.BashHelper(c, </span>&cmdLenth, op, &<span style="color: rgba(0, 0, 0, 1)">outputLength);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Marshal.PtrToStringAnsi((IntPtr)op);
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">unsafe</span> <span style="color: rgba(0, 0, 255, 1)">extern</span> <span style="color: rgba(0, 0, 255, 1)">void</span> BashHelper(<span style="color: rgba(0, 0, 255, 1)">char</span>* cmdStr, <span style="color: rgba(0, 0, 255, 1)">int</span>* cmdLength, <span style="color: rgba(0, 0, 255, 1)">char</span>* output, <span style="color: rgba(0, 0, 255, 1)">int</span>*<span style="color: rgba(0, 0, 0, 1)"> length);
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cmdStr = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/bin/ls /</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> output =<span style="color: rgba(0, 0, 0, 1)"> Clib.InvokeBash(cmdStr);
Console.Write(output);</span></pre>
</div>
<p> 完成之后,我们再次在Shell中调用。</p>
<p><img src="//images0.cnblogs.com/blog2015/499899/201505/032339430058122.png"></p>
<p> 成功执行BashShell命令并把返回输出重定向到C#中。</p>
<p> 可能有读者会有这么一个疑问:“这跟直接写BashShell没啥差别啊?!”此言差矣,C#有C#的优势,Bash有Bash的优势,将两者结合起来后,可以形成互补,利用Bash可以快速的操作Linux,而一些Bash无法提供的功能,譬如写入数据库、调用某些服务的API、做其他BashShell无法做的事情等。</p>
<hr>
<p> 好的,本篇就写这么多了,非C内行,文中可能有不科学之处,仅提供思路,勿拍砖哈。谢谢。</p>
<p> 原文地址:http://jhonge.net/Home/Single2/1938</p><br><br>
来源:https://www.cnblogs.com/xiaodiejinghong/p/4475066.html
頁:
[1]