高級語言與shell的交互

高級語言與shell的交互 

 由於項目需要,最近研究了高級語言調用其他一些腳本的方法,這裏主要介紹兩個語言,分別是Java 和 C語言。
 
 
1.Java調用shell
   Java語言以其跨平臺性和簡易性而著稱,在Java裏面的lang包裏(java.lang.Runtime)提供了一個允許Java程序與該程序所運行的環境交互的接口,這就是Runtime類,在Runtime類裏提供了獲取當前運行環境的接口。 其中的exec函數返回一個執行shell命令的子進程。exec函數的具體實現形式有以下幾種:
   
public Process exec(String command) throws IOException
public Process exec(String command,String[] envp) throws IOException
public Process exec(String command,String[] envp,File dir) throws IOException
public Process exec(String[] cmdarray) throws IOException
public Process exec(String[] cmdarray, String[] envp) throws IOException
public Process exec(String[] cmdarray, String[] envp,File dir) throws IOException
 
   我們在這裏主要用到的是第一個和第四個函數,具體方法很簡單,就是在exec函數中傳遞一個代表命令的字符串。exec函數返回的是一個Process類型的類的實例。Process類主要用來控制進程,獲取進程信息等作用。(具體信息及其用法請參看Java doc)。
 
1)執行簡單的命令的方法:
代碼如下:
        try
        {
            String commands = "ls -l";
            Process process = Runtime.getRuntime().exec (commands);
            // for showing the info on screen 
            InputStreamReader ir=new InputStreamReader(process.getInputStream());
            BufferedReader input = new BufferedReader (ir);
            String line;
            while ((line = input.readLine ()) != null){
                System.out.println(line);
            }
        }//end try
        catch (java.io.IOException e){
            System.err.println ("IOException " + e.getMessage());
        }

  上面的代碼首先是聲明瞭一個代表命令的字符串commands,它代表了ls -l 這個命令。之後我們用Runtime.getRuntime().exec(commands)來生成一個子進程來執行這個命令,如果這句話運行成功,則 命令 ls -l 運行成功(由於沒有讓它顯示,不會顯示ls -l 的結果)。後面的流操作則是獲取進程的流信息,並把它們一行行輸出到屏幕。

2)執行帶有參數的命令(尤其是參數需要用引號的)時則需要用String的數組來表示整個命令,而且要用轉義符把引號的特殊含義去除,例如我們要執行 find / -name "*mysql*" -print 時,用如下代碼
        try
        {
            String[] commands = new String[]{"find",".","-name","*mysql*","-print"};
            Process process = Runtime.getRuntime().exec (commands);
            InputStreamReader ir=new InputStreamReader(process.getInputStream());
            BufferedReader input = new BufferedReader (ir);
            String line;
            while ((line = input.readLine ()) != null){
                System.out.println(line);
            }
         }//end try
        catch (java.io.IOException e){
            System.err.println ("IOException " + e.getMessage());
 
3)執行一個自己寫的腳本
非常簡單,只需要在構造commands時寫出它的詳細路徑和文件名,及參數等。
   
   try
        {
            String commands = "/root/test/checkfile.sh";
            Process process = Runtime.getRuntime().exec (commands);
            InputStreamReader ir=new InputStreamReader(process.getInputStream());
            BufferedReader input = new BufferedReader (ir);
            String line;
            while ((line = input.readLine ()) != null){
                System.out.println(line);
            }
         }//end try
        catch (java.io.IOException e){
            System.err.println ("IOException " + e.getMessage());
 
如果命令中有參數,同2)要用數組的形式
 
 
 
2.C程序調用shell
 
C程序調用shell腳本共有三種方式:system()、popen()、exec系列函數

1)system(shell命令或shell腳本路徑);
    
   system()會調用fork()產生子進程,由子進程來調用/bin/sh-c string來執行參數string字符串所代表的命令,此命令執行完後隨即返回原調用的進程。在調用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被忽略。
    
    返回值:如果system()在調用/bin/sh時失敗則返回127,其他失敗原因返回-1。若參數string爲空指針(NULL),則返回非零值。如果 system()調用成功則最後會返回執行shell命令後的返回值,但是此返回值也有可能爲system()調用/bin/sh失敗所返回的127,因此最好能再檢查errno 來確認執行成功。
 
   system命令以其簡單高效的作用得到很很廣泛的應用,下面是一個例子

例:在~/test/目錄下有shell腳本test.sh,內容爲
#!bin/bash
#test.sh
echo hello
 
在同層目錄下新建一個c文件system_test.c,內容爲:
 
#include<stdlib.h>
int main()
{
  system("~/test/test.sh");
}
 
 
執行結果如下:
 
[root@localhost test]$gcc system_test.c -o system_test  
[root@localhost test]$./system_test
hello
[root@localhost test]$

2)popen(char *command,char *type)   
 
    popen()會調用fork()產生子進程,然後從子進程中調用/bin/sh -c來執行參數command的指令。參數type可使用“r”代表讀取,“w”代表寫入。依照此type值,popen()會建立管道連到子進程的標準輸出設備或標準輸入設備,然後返回一個文件指針。隨後進程便可利用此文件指針來讀取子進程的輸出設備或是寫入到子進程的標準輸入設備中。此外,所有使用文件指針(FILE*)操作的函數也都可以使用,除了fclose()以外。
 
    返回值:若成功則返回文件指針,否則返回NULL,錯誤原因存於errno中。注意:在編寫具SUID/SGID權限的程序時請儘量避免使用popen(),popen()會繼承環境變量,通過環境變量可能會造成系統安全的問題。
 
例:C程序popentest.c內容如下:
    #include<stdio.h>
    main
    {
        FILE * fp;
        charbuffer[80];
        fp=popen(“~/myprogram/test.sh”,”r”);
        fgets(buffer,sizeof(buffer),fp);
        printf(“%s”,buffer);
        pclose(fp);
    }
 
 
執行結果如下:
 
[root@localhost test]$ vim popentest.c
[root@localhost test]$ gcc popentest.c -o popentest
[root@localhost test]$ ./popentest
/root/test
[root@localhost test]$
 
對於exec系列函數這裏就不做具體介紹了。
希望這些東西對大家有用。
本文參考了下面這片文章,謝過作者。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章