使用C#給Linux寫Shell腳本(下篇)


    在上篇的《使用C#給Linux寫Shell腳本》結尾中,我們留下了一個關於C#如何調用BashShell的問題。在文章發布之后,我留意到有讀者留言推薦使用“Pash”(一款類PowerShell的東西),在我下載並安裝了該項目之后,嘗試之下發現這仍然不是我們想要的。似乎C#還真的沒有提供這種(輸出重定向)功能,這也迫使我們采取了其他方式來實現。在本篇中,我們將提升“恫嚇”等級並順帶把這個難題一並解決,各位看官請系好安全帶。

    本篇中,我們將介紹:

      (1)、C#直接調用BashShell所遭遇的問題

      (2)、使用C的popen方式調用BashShell

      (3)、通過調用C來間接的調用BashShell


    一、C#直接調用BashShell所產生的問題

    使用C#調其他應用,毫無疑問最直接的方法就是“System.Diagnostics”中的Process.Start了。但當我們使用Process.Start時,卻發現連最簡單的命令都無法調用,更無從談起調用並接受返回了。

    上圖為其中一種錯誤(當然還會有更多的問題出現,這里就不列舉了)。

 

    二、使用C的popen方式調用

    正由於Process.Start無法直接調用BashShell的命令,我們需要繞道而行。

    我們先看下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管道並完成輸出重定向。

 

    三、通過調用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM