原文 http://blog.chinaunix.net/u1/42963/showart_709425.html
由于項(xiàng)目需要,最近研究了高級(jí)語言調(diào)用其他一些腳本的方法,這里主要介紹兩個(gè)語言,分別是Java 和 C語言。
1.Java調(diào)用shell
Java語言以其跨平臺(tái)性和簡(jiǎn)易性而著稱,在Java里面的lang包里(java.lang.Runtime)提供了一個(gè)允許Java程序與該程序所運(yùn)行的環(huán)境交互的接口,這就是Runtime類,在Runtime類里提供了獲取當(dāng)前運(yùn)行環(huán)境的接口。 其中的exec函數(shù)返回一個(gè)執(zhí)行shell命令的子進(jìn)程。exec函數(shù)的具體實(shí)現(xiàn)形式有以下幾種:
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
我們?cè)谶@里主要用到的是第一個(gè)和第四個(gè)函數(shù),具體方法很簡(jiǎn)單,就是在exec函數(shù)中傳遞一個(gè)代表命令的字符串。exec函數(shù)返回的是一個(gè)Process類型的類的實(shí)例。Process類主要用來控制進(jìn)程,獲取進(jìn)程信息等作用。(具體信息及其用法請(qǐng)參看Java doc)。
1)執(zhí)行簡(jiǎn)單的命令的方法:
代碼如下:
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());
}
上面的代碼首先是聲明了一個(gè)代表命令的字符串commands,它代表了ls -l 這個(gè)命令。之后我們用Runtime.getRuntime().exec(commands)來生成一個(gè)子進(jìn)程來執(zhí)行這個(gè)命令,如果這句話運(yùn)行成功,則 命令 ls -l 運(yùn)行成功(由于沒有讓它顯示,不會(huì)顯示ls -l 的結(jié)果)。后面的流操作則是獲取進(jìn)程的流信息,并把它們一行行輸出到屏幕。
2)執(zhí)行帶有參數(shù)的命令(尤其是參數(shù)需要用引號(hào)的)時(shí)則需要用String的數(shù)組來表示整個(gè)命令,而且要用轉(zhuǎn)義符把引號(hào)的特殊含義去除,例如我們要執(zhí)行 find / -name "*mysql*" -print 時(shí),用如下代碼
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)執(zhí)行一個(gè)自己寫的腳本
非常簡(jiǎn)單,只需要在構(gòu)造commands時(shí)寫出它的詳細(xì)路徑和文件名,及參數(shù)等。
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());
如果命令中有參數(shù),同2)要用數(shù)組的形式。
2.C程序調(diào)用shell
C程序調(diào)用shell腳本共有三種方式:system()、popen()、exec系列函數(shù)
1)system(shell命令或shell腳本路徑);
system()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,由子進(jìn)程來調(diào)用/bin/sh-c string來執(zhí)行參數(shù)string字符串所代表的命令,此命令執(zhí)行完后隨即返回原調(diào)用的進(jìn)程。在調(diào)用system()期間SIGCHLD 信號(hào)會(huì)被暫時(shí)擱置,SIGINT和SIGQUIT 信號(hào)則會(huì)被忽略。
返回值:如果system()在調(diào)用/bin/sh時(shí)失敗則返回127,其他失敗原因返回-1。若參數(shù)string為空指針(NULL),則返回非零值。如果 system()調(diào)用成功則最后會(huì)返回執(zhí)行shell命令后的返回值,但是此返回值也有可能為system()調(diào)用/bin/sh失敗所返回的127,因此最好能再檢查errno 來確認(rèn)執(zhí)行成功。
system命令以其簡(jiǎn)單高效的作用得到很很廣泛的應(yīng)用,下面是一個(gè)例子
例:在~/test/目錄下有shell腳本test.sh,內(nèi)容為
#!bin/bash
#test.sh
echo hello
在同層目錄下新建一個(gè)c文件system_test.c,內(nèi)容為:
#include<stdlib.h>
int main()
{
system("~/test/test.sh");
}
執(zhí)行結(jié)果如下:
[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()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,然后從子進(jìn)程中調(diào)用/bin/sh -c來執(zhí)行參數(shù)command的指令。參數(shù)type可使用“r”代表讀取,“w”代表寫入。依照此type值,popen()會(huì)建立管道連到子進(jìn)程的標(biāo)準(zhǔn)輸出設(shè)備或標(biāo)準(zhǔn)輸入設(shè)備,然后返回一個(gè)文件指針。隨后進(jìn)程便可利用此文件指針來讀取子進(jìn)程的輸出設(shè)備或是寫入到子進(jìn)程的標(biāo)準(zhǔn)輸入設(shè)備中。此外,所有使用文件指針(FILE*)操作的函數(shù)也都可以使用,除了fclose()以外。
返回值:若成功則返回文件指針,否則返回NULL,錯(cuò)誤原因存于errno中。注意:在編寫具SUID/SGID權(quán)限的程序時(shí)請(qǐng)盡量避免使用popen(),popen()會(huì)繼承環(huán)境變量,通過環(huán)境變量可能會(huì)造成系統(tǒng)安全的問題。
例:C程序popentest.c內(nèi)容如下:
#include<stdio.h>
main
{
FILE * fp;
charbuffer[80];
fp=popen(“~/myprogram/test.sh”,”r”);
fgets(buffer,sizeof(buffer),fp);
printf(“%s”,buffer);
pclose(fp);
}
執(zhí)行結(jié)果如下:
[root@localhost test]$ vim popentest.c
[root@localhost test]$ gcc popentest.c -o popentest
[root@localhost test]$ ./popentest
/root/test
[root@localhost test]$
對(duì)于exec系列函數(shù)這里就不做具體介紹了。
希望這些東西對(duì)大家有用。
本文參考了下面這片文章,謝過作者。