在上篇的《使用C#給Linux寫Shell腳本》結尾中,咱們留下了一個關於C#如何調用BashShell的問題。在文章發佈以後,我留意到有讀者留言推薦使用「Pash」(一款類PowerShell的東西),在我下載並安裝了該項目以後,嘗試之下發現這仍然不是咱們想要的。彷佛C#還真的沒有提供這種(輸出重定向)功能,這也迫使咱們採起了其餘方式來實現。在本篇中,咱們將提高「恫嚇」等級並順帶把這個難題一併解決,各位看官請繫好安全帶。shell
本篇中,咱們將介紹:數據庫
(1)、C#直接調用BashShell所遭遇的問題安全
(2)、使用C的popen方式調用BashShell函數
(3)、經過調用C來間接的調用BashShellspa
1、C#直接調用BashShell所產生的問題.net
使用C#調其餘應用,毫無疑問最直接的方法就是「System.Diagnostics」中的Process.Start了。但當咱們使用Process.Start時,卻發現連最簡單的命令都沒法調用,更無從談起調用並接受返回了。3d
上圖爲其中一種錯誤(固然還會有更多的問題出現,這裏就不列舉了)。code
2、使用C的popen方式調用blog
正因爲Process.Start沒法直接調用BashShell的命令,咱們須要繞道而行。get
咱們先看下C語言,C語言調用Shell的方式有多種,咱們選擇了popen函數的方式進行調用,先看一下如下的這個demo:
#include<stdio.h> int main(){ FILE *fp; char buffer[255]; fp=popen("ls /home/le","r"); fread(buffer,255,255,fp); pclose(fp); printf("%s",buffer); }
經過poepn管道並完成輸出重定向。
3、經過調用C來間接調用Shell
既然C已經能夠實現對BashShell的調用已經管道重定向,那咱們則能夠再經過C#調用C的方式,進而間接的完成對BashShell的調用。
咱們先對本身的C函數進行改造,改造後的代碼以下(對具體操做有疑問的讀者可參見《如何讓C爲C#提供函數》):
#include<stdio.h> #include<string.h> void* ConvertToCStr(char* input,char* res,int *length){ int i; for(i=0;i<*length;i++){ res[i]=*(input+2*i); } res[i]='\0'; } void* BashHelper(char* cmdStr,int* cmdLength,char* output,int* length){ FILE* fp; char buffer[*length]; char cmd[*cmdLength+1]; ConvertToCStr(cmdStr,cmd,cmdLength); fp=popen(cmd,"r"); fread(buffer,*length,*length,fp); pclose(fp); strcat(output,buffer); }
一樣的咱們也把C# Shell進行改造(沒有Intellisense果真難寫,我先在控制檯寫好再拷貝過來)
#!/bin/env csharp using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; class Clib { public static string InvokeBash(string cmdStr) { char[] output = new char[255]; unsafe { fixed (char* c = cmdStr) fixed (char* op = output) { int cmdLenth = cmdStr.Length; int outputLength = output.Length; Clib.BashHelper(c, &cmdLenth, op, &outputLength); return Marshal.PtrToStringAnsi((IntPtr)op); } } } [DllImport("/你存放so的地址/shell.so", CallingConvention = CallingConvention.StdCall)] static unsafe extern void BashHelper(char* cmdStr, int* cmdLength, char* output, int* length); } var cmdStr = "/bin/ls /"; var output = Clib.InvokeBash(cmdStr); Console.Write(output);
完成以後,咱們再次在Shell中調用。
成功執行BashShell命令並把返回輸出重定向到C#中。
可能有讀者會有這麼一個疑問:「這跟直接寫BashShell沒啥差異啊?!」此言差矣,C#有C#的優點,Bash有Bash的優點,將二者結合起來後,能夠造成互補,利用Bash能夠快速的操做Linux,而一些Bash沒法提供的功能,譬如寫入數據庫、調用某些服務的API、作其餘BashShell沒法作的事情等。
好的,本篇就寫這麼多了,非C內行,文中可能有不科學之處,僅提供思路,勿拍磚哈。謝謝。
原文地址:http://jhonge.net/Home/Single2/1938